diff --git a/documentation/components/AddBookComponent.html b/documentation/components/AddBookComponent.html new file mode 100644 index 0000000..de5ce36 --- /dev/null +++ b/documentation/components/AddBookComponent.html @@ -0,0 +1,1210 @@ + + +
+ + ++
+ src/app/pages/add-book/add-book.component.ts
+
+
+ OnInit
+
selector | +app-add-book |
+
templateUrl | +./add-book.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, _date: DateService, router: Router)
+ |
+ ||||||||||||
+ + | +||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + addCategory + + + + | +||||||
+addCategory(index: number)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + removeCategory + + + + | +||||||
+removeCategory(index: number)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + saveBook + + + + | +
+saveBook()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + uploadFile + + + + | +||||
+uploadFile(event)
+ |
+ ||||
+ + | +||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : FormGroup
+
+ |
+
+ + | +
+ + + + Public + router + + + + | +
+ router:
+ |
+
+ Type : Router
+
+ |
+
+ + | +
+ + + + selected_categories + + + + | +
+ selected_categories:
+ |
+
+ Type : string[]
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + today + + + + | +
+ today:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + uid + + + + | +
+ uid:
+ |
+
+ Type : string
+
+ |
+
+ + | +
+ + + + urlImgs + + + + | +
+ urlImgs:
+ |
+
+ Type : any[]
+
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FormGroup, FormControl, Validators } from '@angular/forms';
+
+// INTERFACE
+import { Books } from "../../interface/books.interface";
+
+// SERVICE
+import { DatabaseService } from "../../services/database.service";
+import { DateService } from 'src/app/services/date.service';
+
+// ANGULARFIRE2
+import * as firebase from 'firebase';
+
+// SWEET ALERT
+import swal from 'sweetalert';
+
+@Component({
+ selector: 'app-add-book',
+ templateUrl: './add-book.component.html'
+})
+export class AddBookComponent implements OnInit {
+
+ form:FormGroup;
+ urlImgs:any[]; // Almacena las rutas de imagenes, para ser guardadas en Storage
+ uid:string; // uid usuario actual
+ today:any;
+ categories:Array<string>=["Antiguedades y Coleccionables", "Arquitectura", "Arte", "Artes Escénicas", "Biografía y Autobiografía", "Casa y Hogar", "Ciencia", "Ciencias Políticas", "Ciencias Sociales", "Cocina", "Comida y Bebestibles", "Colecciones Literarias", "Cómics y Novelas Gráficas", "Computación e Internet", "Crímenes", "Crítica Literaria", "Cuerpo", "Mente y Espíritu", "Deportes y Recreación", "Drama", "Educación", "Estudio de Lenguas Extranjeras", "Ensayos Académicos", "Familia y Relaciones", "Ficción", "Ficción Adolescente", "Ficción para Niños", "Filosofía", "Fotografía", "Historia y Geografía", "Humor", "Jardinería", "Juegos", "Lectura escolar", "Lengua y Literatura", "Leyes", "Manualidades y Hobbies", "Mascotas y Animales", "Matemáticas", "Medicina", "Música", "Naturaleza y Aire libre", "Negocios y Economía", "Niños y Jóvenes", "Papelería", "Poesía", "Psicología", "Religión y Espiritualidad", "Salud y Bienestar", "Tecnología", "Transporte", "Viajes"];
+ selected_categories:string[] = [];
+
+ constructor( private _dbService:DatabaseService,
+ private _date:DateService,
+ public router:Router ) {
+ }
+
+ ngOnInit() {
+ this.form = new FormGroup({
+ title: new FormControl(undefined, Validators.required),
+ author: new FormControl(undefined, Validators.required),
+ editorial: new FormControl(undefined, Validators.required),
+ type: new FormControl(undefined, Validators.required),
+ genres: new FormControl(this.selected_categories),
+ transaction: new FormControl(undefined, Validators.required),
+ price: new FormControl(undefined),
+ language: new FormControl(undefined, Validators.required),
+ original: new FormControl(undefined, Validators.required),
+ num_page: new FormControl(undefined, Validators.required),
+ comment: new FormControl(undefined),
+ images: new FormControl(undefined),
+ date: new FormControl(this._date.actual_date())
+ });
+
+ this.uid = JSON.parse(localStorage.getItem('user')).uid;
+ }
+
+ // Guarda un libro nuevo en la DB
+ saveBook(){
+ if( this.form.invalid ){
+ swal(
+ 'Debe completar el formulario',
+ 'Debe ingresar todos los campos de este formulario',
+ 'warning'
+ );
+ return;
+ }
+
+ // Carga las imagenes en el formulario para luego subirlas
+ this.form.patchValue({
+ images: this.urlImgs
+ });
+
+ let book:Books = this.form.value; // Guarda el formulario para validar
+
+ // Agrega la referencia al usuario propietario del libro
+ let user = JSON.parse( localStorage.getItem( "user" ));
+ book.user = this._dbService.afs.collection('users').doc(user.uid).ref;
+
+ // Convierte el id de Firebase en uid + fechahora
+ book.id = user.uid + "-" + new Date().valueOf() ;
+ book.uid = user.uid;
+ book.status = 'available';
+
+ // Guarda el libro
+ this._dbService.addData('books', book)
+ .then( () => {
+ console.log("se guardó el libro");
+ swal('Libro registrado con éxito', book.title, 'success');
+ this.router.navigate([ '/home' ]);
+ })
+ .catch( (err) => {
+ console.log("error al guardar libros", err)
+ swal("Error", "No se ha podido guardar el nuevo libro", "warning");
+ });
+ }
+
+ // Carga las imagenes al storage de Firebase
+ uploadFile(event) {
+ let files = event.target.files;
+ let url = []; // Guarda las imagenes correctas para luego subirlas
+ let aux = false; // Sirve para que no se cargen imagenes si existe aunque sea una incorrecta
+
+ for( let i=0; i<files.length; i++ ){
+ const separatedFile = files[i].name.split('.');
+ const extension = separatedFile[separatedFile.length - 1];
+
+ // Tipos de archivo válidos para las imagenes
+ const typeValid = ['jpg', 'jpeg', 'png'];
+
+ // si las imagenes no son validas se termina el proceso
+ if( typeValid.indexOf( extension ) <= -1 ){
+ swal(
+ 'Error al ingresar imagen',
+ 'Extensiones válidas (png, jpg, jpeg), vuelva a intentarlo',
+ 'error'
+ );
+ aux = true;
+ return;
+ }
+ }
+
+ if( !aux ){
+ const storageRef = firebase.storage().ref();
+ let upload = false;
+ for(let i=0; i<files.length; i++){
+
+ let filePath = `${this.uid}-${new Date().valueOf()}`;
+ console.log(filePath)
+
+ const uploadTask:firebase.storage.UploadTask =
+ storageRef.child(`images/${ filePath }`)
+ .put(files[i])
+
+ uploadTask.on('state_changed',
+ () => {}, // Manejo de carga
+ (error) => { // Manejo de errores
+ console.log('Error al cargar imagen' ,error);
+ swal('Error al cargar imagenes', 'Por favor, vueva a intentarlo', 'error');
+ },
+ () => { // Éxito
+ uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
+ url.push( downloadURL );
+ if(i === files.length-1) {
+ console.log("Imagenes cargadas");
+ swal('Éxito', 'Imagenes cargadas con exito', 'success');
+ }
+ });
+ }
+ );
+ }
+ this.urlImgs = url;
+ }
+ }
+
+ // Agrega una categoría al cuadro de categorías del libro
+ addCategory(index:number){
+ this.selected_categories.push(this.categories[index]);
+ this.categories.splice(index, 1);
+ // TODO: Ordenar por index
+ }
+
+ // Remueve una categoría del cuadro de categorías del libro
+ removeCategory(index:number){
+ this.categories.push(this.selected_categories[index]);
+ this.selected_categories.splice(index, 1);
+ console.log(this.selected_categories);
+ }
+}
+
+
+ <div class="container" style="background-color: #ffffff;">
+ <h1 style="padding-top:30px;">Agregar libro</h1>
+ <form class="form-material m-t-40" [formGroup]="form" (ngSubmit)="saveBook()" novalidate="novalidate">
+ <div class="row">
+ <!-- Inicio col 1 -->
+ <div class="col-6">
+ <div class="form-group">
+ <label>Título del texto</label>
+ <input type="text" formControlName="title"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: Harry Potter">
+ </div>
+
+ <div class="form-group">
+ <label>Autor del texto</label>
+ <input type="text" formControlName="author"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: J. K. Rowling">
+ </div>
+
+ <div class="form-group">
+ <label>Editorial del texto</label>
+ <input type="text" formControlName="editorial"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: Salamandra">
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Tipo de elemento</label>
+ <select class="form-control" formControlName="type">
+ <option value="Libro">Libro</option>
+ <option value="Cómic">Cómic</option>
+ <option value="Lectura especializada">Lectura especializada</option>
+ <option value="Literatura infantil">Literatura infantil</option>
+ <option value="Otro">Otro</option>
+ </select>
+ </div>
+
+ <!-- TODO: Dejar esto más bonito -->
+ <div class="form-group">
+ <input id="file" type="file" style="padding-top: 25px;" (change)="uploadFile($event)" multiple>
+ </div>
+
+ </div>
+ <!-- Fin col 1 -->
+
+ <!-- Inicio col 2 -->
+ <div class="col-6">
+ <div class="form-group border-input-custom">
+ <label>Tipo de transacción</label>
+ <select class="form-control" formControlName="transaction">
+ <option value="Intercambio">Intercambio</option>
+ <option value="Venta">Venta</option>
+ <option value="Ambos">Ambos</option>
+ </select>
+ </div>
+
+ <div class="form-group" *ngIf="form.value.transaction === 'Venta'">
+ <label>Precio</label>
+ <input formControlName="price" onlynumber="true" minlength="3" maxlength="6"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: 5000">
+ </div>
+
+ <div class="form-group" *ngIf="form.value.transaction === 'Ambos'">
+ <label>Precio</label>
+ <input formControlName="price" onlynumber="true" minlength="3" maxlength="6"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: 5000">
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Idioma</label>
+ <select class="form-control"
+ formControlName="language">
+ <option value="Español">Español</option>
+ <option value="Inglés">Inglés</option>
+ <option value="Otro">Otro</option>
+ </select>
+ </div>
+
+ <div class="form-group border-input-custom"
+ name="original">
+ <label>Texto original</label>
+ <select class="form-control" formControlName="original">
+ <option value="Sí">Sí</option>
+ <option value="No">No</option>
+ </select>
+ </div>
+
+ <div class="form-group">
+ <label>Cantidad de páginas</label>
+ <input formControlName="num_page" onlynumber="true" minlength="2" maxlength="5"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: 324">
+ </div>
+
+ <div class="form-group">
+ <label>Comentario</label>
+ <textarea class="form-control border-input-custom" formControlName="comment" rows="2"
+ placeholder="Ej.: El libro se encuentra en buen estado, leído solo una vez.">
+ </textarea>
+ </div>
+ </div>
+ <!-- Fin col 2 -->
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Categoría a la que pertenece</label>
+ <!-- FIXME: Revisar po jjj -->
+ <div class="ms-container" id="ms-pre-selected-options">
+ <div class="ms-selectable">
+ <select class="ms-list contenedor" multiple='multiple'>
+ <option [value]='c' class="ms-elem-selectable" *ngFor="let c of categories; let i = index;"
+ (click)="addCategory(i)"> {{ c }} </option>
+ </select>
+ </div>
+ <div class="ms-selection">
+ <select class="ms-list contenedor" multiple='multiple' formControlName="genres" style="margin-left: 35px;">
+ <option [value]='sc' class="ms-elem-selection" *ngFor="let sc of selected_categories; let i = index;"
+ (click)="removeCategory(i)"> {{ sc }} </option>
+ </select>
+ </div>
+ </div>
+ </div>
+
+ <div class="row justify-content-md-center">
+ <div class="form-group">
+ <button type="submit" class="btn btn-outline-info">Guardar</button>
+ </div>
+ </div>
+ </form>
+</div>
+
+
+
+
+
+
+ +
+ src/app/admin/admin.component.ts
+
+
+ OnInit
+
selector | +app-admin |
+
templateUrl | +./admin.component.html |
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ Defined in src/app/admin/admin.component.ts:11
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/admin/admin.component.ts:15
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+// Inicializa los plugins
+declare function init_plugins();
+
+@Component({
+ selector: 'app-admin',
+ templateUrl: './admin.component.html',
+ styles: []
+})
+export class AdminComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ init_plugins();
+ }
+
+}
+
+ <div id="main-wrapper">
+ <app-header></app-header>
+ <app-sidebar></app-sidebar>
+
+ <!-- ============================================================== -->
+ <!-- Page wrapper -->
+ <!-- ============================================================== -->
+ <div class="page-wrapper">
+ <!-- ============================================================== -->
+ <!-- Container fluid -->
+ <!-- ============================================================== -->
+ <div class="container-fluid">
+
+ <!-- ============================================================== -->
+ <!-- Start Page Content -->
+ <!-- ============================================================== -->
+ <router-outlet></router-outlet>
+ <!-- ============================================================== -->
+ <!-- End Page Content -->
+ <!-- ============================================================== -->
+ </div>
+ <!-- ============================================================== -->
+ <!-- END Container fluid -->
+ <!-- ============================================================== -->
+ </div>
+ <!-- ============================================================== -->
+ <!-- END Page wrapper -->
+ <!-- ============================================================== -->
+</div>
+ +
+ src/app/app.component.ts
+
selector | +app-root |
+
styleUrls | +./app.component.css |
+
templateUrl | +./app.component.html |
+
+constructor()
+ |
+
+ Defined in src/app/app.component.ts:8
+ |
+
import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+
+ constructor(){
+ if(JSON.parse(localStorage.getItem('session')) === null) {
+ localStorage.setItem('session', JSON.stringify({
+ session: false,
+ rememberMe: false
+ }));
+ }
+ }
+}
+ <router-outlet></router-outlet>
+
+ ./app.component.css
+
+ +
+ src/app/components/card-book/card-book.component.ts
+
+
+ OnInit
+
selector | +app-card-book |
+
templateUrl | +./card-book.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+ Inputs+ |
+
+ + | +
+constructor(_date: DateService, _dbService: DatabaseService)
+ |
+ |||||||||
+ + | +|||||||||
+
+ Parameters :
+
+
|
+
+
+ booksHome
+ |
+
+
+ Type : |
+
+ + | +
+
+ type
+ |
+
+
+ Type : |
+
+ + | +
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + openBook + + + + | +||||||
+openBook(book: any)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + reportImage + + + + | +||||||
+reportImage(book_m: any)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + reportUser + + + + | +||||||
+reportUser(book_m: any)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + sendMessage + + + + | +
+sendMessage()
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ + + + actual_user + + + + | +
+ actual_user:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + book_modal + + + + | +
+ book_modal:
+ |
+
+ Type : Books
+
+ |
+
+ Default value : {
+ author: '',
+ title: '',
+ editorial: '',
+ type: '',
+ categories: [],
+ language: '',
+ num_page: 0,
+ original: false,
+ transaction: '',
+ user: '',
+ id: '',
+ comment: '',
+ price: 0,
+ images: [],
+ date: ''
+ }
+ |
+
+ + | +
+ + + + books + + + + | +
+ books:
+ |
+
+ Type : any[]
+
+ |
+
+ + | +
+ + + + count_book + + + + | +
+ count_book:
+ |
+
+ Type : number
+
+ |
+
+ Default value : 0
+ |
+
+ + | +
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + loading + + + + | +
+ loading:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : true
+ |
+
+ + | +
+ + + + today + + + + | +
+ today:
+ |
+
+ Type : any
+
+ |
+
+ + | +
import { Component, OnInit, Input } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+
+// INTERFACE
+import { Books, Message, Users, Report } from '../../interface/books.interface';
+
+// SERVICIOS
+import { DatabaseService } from '../../services/database.service';
+import { DateService } from '../../services/date.service';
+
+import swal from 'sweetalert';
+
+@Component({
+ selector: 'app-card-book',
+ templateUrl: './card-book.component.html'
+})
+export class CardBookComponent implements OnInit {
+
+ // Input desde el Home, traen el elemento a mostrar
+ @Input() type:string;
+ @Input() booksHome:any[];
+
+ books:any[]; // array con los books a mostrar
+ loading:boolean = true; // muestra y esconde un loading
+ form:any;
+ actual_user:any;
+ today:any;
+ count_book:number = 0;
+
+ book_modal: Books = {
+ author: '',
+ title: '',
+ editorial: '',
+ type: '',
+ categories: [],
+ language: '',
+ num_page: 0,
+ original: false,
+ transaction: '',
+ user: '',
+ id: '',
+ comment: '',
+ price: 0,
+ images: [],
+ date: ''
+ };
+
+
+
+ constructor( private _date:DateService,
+ private _dbService:DatabaseService) {
+ this.actual_user = JSON.parse(localStorage.getItem('user'));
+ }
+
+ ngOnInit() {
+ setTimeout( () => {
+ if( this.type === 'all' ){
+ this.loading = false;
+ this.books = this.booksHome;
+ }else {
+ let aux = [];
+
+ for(let book of this.booksHome){
+ if( book.transaction === this.type ) aux.push(book);
+ }
+ this.loading = false;
+ this.books = aux;
+ }
+ }, 2000);
+
+ this.form = new FormGroup({
+ text: new FormControl([], Validators.required),
+ transaction: new FormControl(undefined, Validators.required),
+ pref: new FormControl(undefined, Validators.required),
+ station: new FormControl(undefined),
+ hour: new FormControl(undefined),
+ day: new FormControl(undefined),
+ new_price: new FormControl(0),
+ new_text: new FormControl([], Validators.required),
+ })
+
+ }
+
+ // Envía el mensaje desde el usuario actual hacia el usuario dueño del libro
+ sendMessage(){
+ let predet_Message:Message = {
+ transaction: this.form.value.transaction,
+ pref: this.form.value.pref,
+ text: [{
+ [this.actual_user.uid]: this.form.value.text,
+ date: this._date.actual_date()
+ }],
+ date: this._date.actual_date(),
+ book: this.book_modal,
+ user_owner: this.book_modal.user.uid,
+ uid_interested: this.actual_user,
+ status: false,
+ price: this.book_modal.price
+ }
+
+ if(predet_Message.pref === null ){
+ return swal('Error al enviar un mensaje', 'Debe completar todos los campos', 'error');
+ }
+
+
+ if ( this.form.value.transaction == undefined || this.form.value.transaction === null){
+ predet_Message.transaction = this.book_modal.transaction;
+ }
+
+ if ( this.form.value.pref === 'dislike_preferences' ){
+ let new_preferences = this.form.value.station + ' - ' + this.form.value.day + ' - ' + this.form.value.hour;
+ predet_Message.pref = new_preferences;
+ }
+
+ if ( this.form.value.text === 'dislike-price' ){
+ predet_Message.price = this.form.value.price;
+ }
+
+ if ( this.form.value.text === 'new_text' ){
+ predet_Message.text = [{
+ [this.actual_user.uid]: this.form.value.new_text,
+ date: this._date.actual_date()
+ }
+ ];
+ }
+
+ // Envía el mensaje a la DB.
+ this._dbService.addData('messages-transaction', predet_Message)
+ .then( () => swal('Mensaje enviado', 'Su mensaje ha sido enviado con éxito', 'success') )
+ .catch( () => swal('Error', 'Su mensaje no ha podido enviarse, vuelva a intentarlo', 'error') );
+ }
+
+ // Envía el mensaje de reporte del usuario al admin
+ reportUser( book_m:any ){
+
+ let report:Report = {
+ id: this.actual_user.uid + "-" + new Date().valueOf(),
+ day: this._date.actual_day(),
+ hour: this._date.actual_hour(),
+ user: this.actual_user,
+ user_reported: book_m.user,
+ type: "Reporte de usuario",
+ status: "No revisado"
+ }
+ console.log(report);
+ // Envía el mensaje a la DB.
+ this._dbService.addData('reports', report)
+ .then( () => swal('Reporte enviado', 'Muchas gracias por reportar, lo revisaremos en seguida', 'success') )
+ .catch( () => swal('Error', 'Su reporte no ha podido enviarse', 'error') );
+ }
+
+ // Envía el mensaje de reporte de imagen al admin
+ reportImage( book_m:any ){
+
+ let report:Report = {
+ id: this.actual_user.uid + "-" + new Date().valueOf(),
+ day: this._date.actual_day(),
+ hour: this._date.actual_hour(),
+ user: this.actual_user,
+ img: book_m.images,
+ type: "Reporte de imagen",
+ status: "No revisado"
+ }
+ console.log(report);
+ // Envía el mensaje a la DB.
+ this._dbService.addData('reports', report)
+ .then( () => swal('Reporte enviado', 'Muchas gracias por reportar, lo revisaremos en seguida', 'success') )
+ .catch( () => swal('Error', 'Su reporte no ha podido enviarse', 'error') );
+ }
+
+
+ openBook( book:any ) {
+ this.book_modal = book;
+
+ this._dbService.getDataQuery("books", "uid", "==", book.uid)
+ .valueChanges()
+ .subscribe( data => this.count_book = data.length );
+ }
+
+}
+
+ <!-- ============================================================================== -->
+<!-- Loader -->
+<!-- ============================================================================== -->
+<div *ngIf="loading" class="loader-contenedor">
+ <app-loading></app-loading>
+ <p> Buscando libros... </p>
+</div>
+<!-- ============================================================================== -->
+<!-- End loader -->
+<!-- ============================================================================== -->
+
+<!-- ============================================================================== -->
+<!-- Card book -->
+<!-- ============================================================================== -->
+<div class="container-fluid">
+ <div class="row">
+ <div *ngIf="!loading" class="card-columns">
+ <div class="card" style="max-width:18rem;" *ngFor="let book of books; let index = index;">
+ <!-- CARROUSEL BOOK IMAGES -->
+ <div id="carouselExampleFade-{{index}}" class="carousel slide carousel-fade" data-ride="carousel">
+ <div class="carousel-inner">
+ <div class="carousel-item" *ngFor="let img of book.images; let i=index;" [ngClass]="{'active': i===0}" >
+ <img class="d-block img-carousel" [src]="img">
+ </div>
+ </div>
+ <a class="carousel-control-prev" href="#carouselExampleFade-{{index}}" role="button" data-slide="prev">
+ <span class="carousel-control-prev-icon" aria-hidden="true"></span>
+ </a>
+ <a class="carousel-control-next" href="#carouselExampleFade-{{index}}" role="button" data-slide="next">
+ <span class="carousel-control-next-icon" aria-hidden="true"></span>
+ </a>
+ </div>
+ <!-- END CARROUSEL BOOK IMAGES -->
+
+ <!-- TEXT CARD -->
+ <div class="card-body">
+ <h5 class="card-title">Título: {{ book.title | titlecase }}</h5>
+ <p class="card-text">Autor/a: {{ book.author | titlecase }}</p>
+ <p class="card-text">Editorial: {{ book.editorial | titlecase }}</p>
+ <p class="card-text">Fecha publicación: {{ book.date }}</p>
+ <p class="card-text" *ngIf="book.transaction == 'Ambos' || book.transaction == 'Venta'">Valor: ${{ book.price | thousands }}</p>
+ <p class="card-text">Dueño: {{book.user.name | titlecase }} {{book.user.last_name1 | titlecase }} {{book.user.last_name2 | titlecase }}</p>
+ <button *ngIf="book.uid === actual_user.uid" class="btn btn-outline-info col-md-12" data-toggle="modal"
+ data-target="#showBook" type="button" (click)="openBook( book )">Ver libro</button>
+ <button *ngIf="book.uid !== actual_user.uid" class="btn btn-outline-info col-md-6" data-toggle="modal"
+ data-target="#showBook" type="button" (click)="openBook( book )">Ver libro</button>
+ <button *ngIf="book.uid !== actual_user.uid"
+ class="btn btn-outline-info col-md-6" data-toggle="modal"
+ data-target="#contactOwner" type="button" (click)="book_modal=book">Contactar</button>
+ </div>
+ <!-- END TEXT CARD -->
+ </div>
+ </div>
+ </div>
+</div>
+
+<!-- ============================================================================================================== -->
+<!-- Modal show book -->
+<!-- ============================================================================================================== -->
+<div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" id="showBook"
+ aria-labelledby="myLargeModalLabel" aria-hidden="true" style="display: none;">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myLargeModalLabel"> {{ book_modal.title | titlecase }}</h4>
+ <div class="other-header">
+
+ <button type="button" aria-expanded="false" aria-haspopup="true" class="close waves-effect" data-toggle="dropdown">
+ <i class="fa fa-angle-down"></i>
+ </button>
+ <!-- ====================================================================== -->
+ <!-- Little modal to report -->
+ <!-- ====================================================================== -->
+ <div class="dropdown-menu dropdown-menu-right mailbox animated bounceInDown">
+ <ul style="padding: 0%!important; margin-bottom: 0 !important;">
+ <div class="message-center">
+ <a (click)=reportUser(book_modal)>
+ <div class="btn btn-danger btn-circle"><i class="ti-user"></i></div>
+ <h5 style="display: inline; margin-left: 20px;">Reportar usuario</h5>
+ </a>
+ <a (click)=reportImage(book_modal)>
+ <div class="btn btn-danger btn-circle"><i class="fa fa-file-image-o"></i></div>
+ <h5 style="display: inline; margin-left: 20px;">Reportar imagen</h5>
+ </a>
+ </div>
+ </ul>
+ </div>
+
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ </div>
+ <!-- ====================================================================== -->
+ <!-- End little modal to report -->
+ <!-- ====================================================================== -->
+
+ </div>
+
+ <div class="modal-body">
+ <app-one-book [book]="book_modal"></app-one-book>
+ </div>
+ <!-- ====================================================================== -->
+ <!-- Profile collapse -->
+ <!-- ====================================================================== -->
+ <div id="accordion">
+ <div class="card">
+ <div class="card-header" id="headingOne">
+ <h5 class="mb-0">
+ <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
+ Ver perfil del dueño
+ </button>
+ </h5>
+ </div>
+ <div id="collapseOne" class="collapse " aria-labelledby="headingOne" data-parent="#accordion">
+ <div class="card-body">
+ <!-- ====================================================================== -->
+ <!-- Show profile -->
+ <!-- ====================================================================== -->
+ <div class="col-12">
+ <div class="card">
+ <div class="card-body row">
+ <div class="col-md-6" align="center">
+ <img [src]="book_modal.user.img" class="img-circle" width="150" />
+ <h4 class="card-title">
+ {{ book_modal.user.name | titlecase }} {{ book_modal.user.last_name1 | titlecase }} {{ book_modal.user.last_name2 | titlecase }} </h4>
+ <div class="row text-center justify-content-md-center">
+ <div class="col-4">
+ <a href="javascript:void(0)" class="link">
+ <i class="fa fa-book"></i>
+ <font class="font-medium"> {{ count_book }}</font>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <small class="text-muted">Correo electrónico</small>
+ <h6> {{ book_modal.user.email }} </h6>
+ <small class="text-muted p-t-30 db">Teléfono de contacto</small>
+ <h6> {{ book_modal.user.phone }} </h6>
+ <small class="text-muted p-t-30 db">Usuario creado el</small>
+ <h6> {{ book_modal.user.created_date }} </h6>
+ </div>
+ </div>
+ <!-- TODO: Revisar que esté aparezcan todas las cat. Copiar en modal de cardbook -->
+ <div class="card-body">
+ <small class="text-muted">Categorías favoritas:</small>
+ <ul>
+ <li>
+ <h6>{{ book_modal.user.categories }}</h6>
+ </li>
+ </ul>
+ </div>
+ <div class="card-body">
+ <div class="dropdown-divider"></div>
+ <small class="text-muted p-t-30 db">Redes sociales</small><br/>
+ <button class="btn btn-circle btn-secondary" style="margin-left: 15px;"><i class="fa fa-facebook"></i></button>
+ <button class="btn btn-circle btn-secondary" style="margin-left: 15px;"><i class="fa fa-twitter"></i></button>
+ <button class="btn btn-circle btn-secondary" style="margin-left: 15px;"><i class="fa fa-youtube"></i></button>
+ </div>
+ </div>
+ </div>
+ <!-- ====================================================================== -->
+ <!-- End show profile -->
+ <!-- ====================================================================== -->
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- ====================================================================== -->
+ <!-- End profile collapse -->
+ <!-- ====================================================================== -->
+ <div class="modal-footer">
+ <button type="button" class="btn btn-danger waves-effect text-left" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- ====================================================================== -->
+<!-- End modal show book -->
+<!-- ====================================================================== -->
+
+
+<!-- ====================================================================== -->
+<!-- Modal contact owner -->
+<!-- ====================================================================== -->
+<div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" id="contactOwner"
+ aria-labelledby="myLargeModalLabel" aria-hidden="true" style="display: none;">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myLargeModalLabel"> Contactar dueño/a </h4>
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ </div>
+ <form [formGroup]="form" (ngSubmit)="sendMessage()">
+ <div class="modal-body">
+ <!-- Transaction -- Ambos -->
+ <div *ngIf="book_modal.transaction == 'Ambos'" >
+ <label>Elija el tipo de transacción que desea</label>
+ <select class="form-control" formControlName="transaction">
+ <option value="Intercambio">Deseo intercambiar el libro</option>
+ <option value="Venta">Deseo comprar el libro</option>
+ </select>
+ </div><br>
+
+ <!-- Preferences -->
+ <label>Seleccione la preferencia que más le acomode</label>
+ <select class="form-control" formControlName="pref">
+ <option value="{{ p.subway_station }}-{{ p.day }}-{{ p.hour }}" *ngFor="let p of book_modal.user.preferences">{{ p.subway_station }} - {{ p.day }} - {{ p.hour }}</option>
+ <option value="dislike_preferences">Ninguna me acomoda</option>
+ </select><br>
+ <br>
+
+ <!-- Custom preferences -->
+ <div *ngIf="form.value.pref === 'dislike_preferences'">
+ <label>Seleccione el horario que desea proponer</label>
+ <div class="row">
+ <!-- Station -->
+ <div class="form-group col-4">
+ <label>Estación de metro</label>
+ <select formControlName="station" id="subway_station" class="form-control">
+ <optgroup label="Línea 1">
+ <option value="República">República</option>
+ <option value="Los Héroes">Los Héroes</option>
+ <option value="La Moneda">La Moneda</option>
+ <option value="Universidad de Chile">Universidad de Chile</option>
+ <option value="Santa Lucía">Santa Lucía</option>
+ <option value="Universidad Católica">Universidad Católica</option>
+ <option value="Baquedano">Baquedano</option>
+ <option value="Salvador">Salvador</option>
+ <option value="Manuel Montt">Manuel Montt</option>
+ <option value="Pedro de Valdivia">Pedro de Valdivia</option>
+ <option value="Los Leones">Los Leones</option>
+ <option value="Tobalaba">Tobalaba</option>
+ </optgroup>
+ <optgroup label="Línea 5">
+ <option value="Quinta Normal">Quinta Normal</option>
+ <option value="Cumming">Cumming</option>
+ <option value="Santa Ana">Santa Ana</option>
+ <option value="Plaza de Armas">Plaza de Armas</option>
+ <option value="Bellas Artes">Bellas Artes</option>
+ <option value="Baquedano">Baquedano</option>
+ <option value="Parque Bustamante">Parque Bustamante</option>
+ <option value="Santa Isabel">Santa Isabel</option>
+ </optgroup>
+ </select>
+ </div>
+ <!-- Day -->
+ <div class="form-group col-md-4">
+ <label>Día</label>
+ <select formControlName="day" id="day" class="form-control">
+ <option value="Lunes">Lunes</option>
+ <option value="Martes">Martes</option>
+ <option value="Miércoles">Miércoles</option>
+ <option value="Jueves">Jueves</option>
+ <option value="Viernes">Viernes</option>
+ <option value="Sábado">Sábado</option>
+ <option value="Domingo">Domingo</option>
+ </select>
+ </div>
+ <!-- Hour -->
+ <div class="form-group col-md-4">
+ <label>Hora</label>
+ <input formControlName="hour" class="form-control" type="time" value="12:00" id="hour">
+ </div>
+ </div>
+ </div>
+
+ <!-- Message -->
+ <div >
+ <label>Seleccione el mensaje a enviar</label>
+ <select class="form-control" formControlName="text">
+ <option value="Deseo establecer la transacción">Deseo establecer la transacción</option>
+ <option *ngIf="book_modal.transaction == 'Venta' || form.value.transaction == 'Venta'"
+ value="dislike-price">No me acomoda el precio</option>
+ <option value="new_text">Deseo escribirle un mensajes personalmente</option>
+ </select>
+ </div><br>
+
+ <!-- Custom price -->
+ <div *ngIf="form.value.text == 'dislike-price'">
+ <label>Ingrese el precio que desea proponer</label>
+ <input type="text" formControlName="new_price"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: 2000">
+ </div>
+
+ <!-- Custom message -->
+ <div *ngIf="form.value.text == 'new_text'">
+ <label>Mensaje</label>
+ <input type="text" formControlName="new_text"
+ class="form-control form-control-line border-input-custom" placeholder="Hola, me gustaría establecer la transacción del libro...">
+ </div>
+ </div>
+
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-outline-info waves-effect text-left">Enviar</button>
+ <button type="button" class="btn btn-danger waves-effect text-left" data-dismiss="modal">Close</button>
+ </div>
+ </form>
+ </div>
+ </div>
+</div>
+<!-- ====================================================================== -->
+<!-- End modal contact owner -->
+<!-- ====================================================================== -->
+
+ +
+ src/app/pages/chats/chats.component.ts
+
selector | +app-chats |
+
styleUrls | +./chats.component.css |
+
templateUrl | +./chats.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, afs: AngularFirestore, _date: DateService, route: ActivatedRoute)
+ |
+ |||||||||||||||
+ Defined in src/app/pages/chats/chats.component.ts:35
+ |
+ |||||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + sendMessage + + + + | +|||||||||
+sendMessage(message: any, text_answer: any)
+ |
+ |||||||||
+ Defined in src/app/pages/chats/chats.component.ts:86
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + showMessages + + + + | +||||||
+showMessages(key: string)
+ |
+ ||||||
+ Defined in src/app/pages/chats/chats.component.ts:67
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + transactionDone + + + + | +
+transactionDone()
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:102
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + actual_user + + + + | +
+ actual_user:
+ |
+
+ Type : string
+
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:33
+ |
+
+ + + + chats + + + + | +
+ chats:
+ |
+
+ Type : Observable<any[]>
+
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:27
+ |
+
+ + + + Private + chatsCollection + + + + | +
+ chatsCollection:
+ |
+
+ Type : AngularFirestoreCollection<any>
+
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:23
+ |
+
+ + + + key + + + + | +
+ key:
+ |
+
+ Type : string
+
+ |
+
+ Default value : undefined
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:35
+ |
+
+ + + + message + + + + | +
+ message:
+ |
+
+ Type : any
+
+ |
+
+ Default value : {
+ uid_interested: ''
+ }
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:28
+ |
+
+ + + + Private + selected_chat + + + + | +
+ selected_chat:
+ |
+
+ Type : AngularFirestoreDocument<any>
+
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:24
+ |
+
+ + + + text_answer + + + + | +
+ text_answer:
+ |
+
+ Type : any
+
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:34
+ |
+
+ + + + uid + + + + | +
+ uid:
+ |
+
+ Type : string
+
+ |
+
+ Defined in src/app/pages/chats/chats.component.ts:32
+ |
+
import { Component } from '@angular/core';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+// ANGULARFIRE2
+import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
+
+// SERVICES
+import { DateService } from '../../services/date.service';
+import { DatabaseService } from 'src/app/services/database.service';
+import { ActivatedRoute } from '@angular/router';
+
+import swal from 'sweetalert';
+
+@Component({
+ selector: 'app-chats',
+ templateUrl: './chats.component.html',
+ styleUrls: ['./chats.component.css']
+})
+export class ChatsComponent {
+
+ // Referencias a las colecciones
+ private chatsCollection: AngularFirestoreCollection<any>;
+ private selected_chat: AngularFirestoreDocument<any>;
+
+ // Observables a las colecciones
+ chats: Observable<any[]>;
+ message:any = {
+ uid_interested: ''
+ };
+
+ uid:string;
+ actual_user:string;
+ text_answer:any;
+ key:string = undefined;
+
+
+ constructor( private _dbService:DatabaseService,
+ private afs:AngularFirestore,
+ private _date:DateService,
+ private route: ActivatedRoute ) {
+
+ this.route.params
+ .subscribe( params => {
+ this.uid = JSON.parse( localStorage.getItem('user') ).uid;
+ this.actual_user = JSON.parse( localStorage.getItem('user') );
+
+ // Si es que viene un mensaje en la ruta lo abrimos
+ if( params['key'] !== undefined && params['key'] !== null ) this.showMessages(params['key']);
+
+ this.chatsCollection = afs.collection('messages-transaction')
+ this.chats = this.chatsCollection.snapshotChanges()
+ .pipe(
+ map( actions => actions.map( a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+
+ // Filtro los datos para obtener solo en los que aparezco
+ if( data.user_owner === this.uid || data.uid_interested.uid === this.uid ){
+ return { key, ...data };
+ }
+ }))
+ );
+ });
+ }
+
+ showMessages( key:string ){
+ this.key = key; // Para que se pueda ver desde el otro método
+
+ this.selected_chat = this.afs.collection<any>('messages-transaction').doc(key);
+ this.selected_chat
+ .valueChanges()
+ .subscribe( data => {
+ this.message = data;
+
+ // Actualiza que el mensaje está leído
+ if( !this.message.status && this.message.text[this.message.text.length - 1][this.uid] === undefined ){
+ this.message.status = true;
+ this._dbService.updateData('messages-transaction', key, this.message);
+ }
+ });
+ }
+
+
+ // Envía el mensaje desde el usuario actual hacia la DB
+ sendMessage(message:any, text_answer:any){
+ if( this.text_answer === undefined || this.text_answer === null || this.text_answer === "" ){
+ swal( 'Debe ingresar un texto para responder', '', 'warning');
+ return;
+ }
+ let answer = {
+ [this.uid]: text_answer,
+ date: this._date.actual_date()
+ }
+
+ this.message.text.push(answer);
+ this.message.status = false; // Para dejar el mensaje nuevo como no leído
+ this._dbService.updateData('messages-transaction', this.key, this.message);
+ this.text_answer = undefined; // Deja en blanco el campo para escribir el mensaje/chat
+ }
+
+ transactionDone(){
+ swal({
+ title: "Confirmas que se estableció la transacción?",
+ text: "Confirmar esto implica que ustedes fijaron horario, día y lugar para la transacción",
+ icon: "warning",
+ buttons: ["Cancelar", "Confirmar"],
+ dangerMode: true
+ })
+ .then(( done ) => {
+ if ( done ) {
+ this._dbService.getDataQuery('books', 'id', '==', this.message.book.id)
+ .snapshotChanges()
+ .pipe(
+ map( actions => actions.map( a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+ return { key, ...data };
+ }))
+ )
+ .subscribe( data => {
+ if( data[0].status === 'completed' ) {
+ swal('Atención', 'Este libro ya fue intercambiado/vendido', 'warning');
+ }else{
+ data[0].status = 'completed';
+ const KEY = data[0].key;
+ delete data[0].key;
+
+ this._dbService.updateData('books', KEY, data[0])
+ .then( () => {
+ swal("Transacción establecida! Gracias por confirmar, estaremos recordandote", {
+ icon: "success",
+ });
+ })
+ .catch( () => swal("Error al confirmar transaccion", "Vuelva a intentarlo", 'error'));
+ }
+ });
+ } else {
+ swal("Recuerda avisarnos cuando establezcan la transacción");
+ }
+ });
+ }
+
+}
+
+
+<!-- ============================================================== -->
+<!-- Start Page Content -->
+<!-- ============================================================== -->
+<div class="row">
+ <div class="col-12">
+ <div class="card m-b-0">
+ <div class="chat-main-box" style="height: 500px;">
+ <!-- =============================================================== -->
+ <!-- Left panel -->
+ <!-- =============================================================== -->
+ <!-- TODO: Hacer que el panel izq se vea mas grande jiji -->
+ <div class="chat-left-aside col-sm-3 col-md-4" style="width: 100%; height: 500px; overflow: scroll;">
+ <div class="open-panel">
+ <i class="ti-angle-right"></i>
+ </div>
+ <div class="chat-left-inner">
+ <div class="form-material">
+ <input class="form-control p-20" type="text" placeholder="Buscar Chat">
+ </div>
+ <ul class="chatonline style-none">
+ <li *ngFor="let c of chats | async" (click)="showMessages(c.key)">
+ <!-- INTERESADO -->
+ <a [ngClass]="{'active': key === c.key}" *ngIf="c !== undefined && uid !== c.uid_interested.uid">
+ <img [src]="c.uid_interested.img" alt="user-img" class="img-circle img-circle-30">
+ <span>
+ {{ c.uid_interested.name | titlecase }}
+ {{ c.uid_interested.last_name1 | titlecase }}
+ {{ c.uid_interested.last_name2 | titlecase }}
+ <small class="text-muted">{{ c.book.title | titlecase }}</small>
+ </span>
+ </a>
+
+ <!-- DUENO -->
+ <a [ngClass]="{'active': key === c.key}" *ngIf="c !== undefined && uid !== c.user_owner">
+ <img [src]="c.book.user.img" alt="user-img" class="img-circle img-circle-30">
+ <span>
+ {{ c.book.user.name | titlecase }}
+ {{ c.book.user.last_name1 | titlecase }}
+ {{ c.book.user.last_name2 | titlecase }}
+ <small class="text-muted">{{ c.book.title | titlecase }}</small>
+ </span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ <!-- =============================================================== -->
+ <!-- End left panel -->
+ <!-- =============================================================== -->
+
+ <!-- =============================================================== -->
+ <!-- Right panel -->
+ <!-- =============================================================== -->
+ <div class="chat-right-aside col-sm-9 col-md-8" style="height: 500px; overflow: scroll;">
+ <div class="chat-main-header"
+ style="position: fixed; width: 100%; z-index: 9; background: white;">
+ <div class="p-20 b-b">
+ <h3 class="box-title">Chat Message</h3>
+ </div>
+ </div>
+ <div *ngIf="key !== undefined; else elseChat" class="chat-rbox m-4">
+ <ul class="chat-list p-10">
+ <!--chat Row -->
+ <div *ngFor="let text of message.text; let i = index;">
+
+ <!-- DERECHA USUARIO ACTIVO -->
+ <li class="reverse">
+ <!-- DUEÑO -->
+ <div *ngIf="message.user_owner === uid && text[message.user_owner] !== undefined">
+ <div class="chat-time">{{ message.date }}</div>
+ <div class="chat-content">
+ <h5>
+ {{ message.book.user.name | titlecase }}
+ {{ message.book.user.last_name1 | titlecase }}
+ {{ message.book.user.last_name2 | titlecase }}
+ </h5>
+ <div class="box bg-light-inverse">{{ text[message.user_owner] }}
+ </div>
+ </div>
+ <div class="chat-img">
+ <img [src]="message.book.user.img" class="img-circle-40"/>
+ </div>
+ </div>
+
+ <!-- INTERESADO -->
+ <div *ngIf="message.uid_interested.uid === uid && text[message.uid_interested.uid] !== undefined">
+ <div class="chat-time">{{ message.date }}</div>
+ <div class="chat-content">
+ <h5>
+ {{ message.uid_interested.name | titlecase }}
+ {{ message.uid_interested.last_name1 | titlecase }}
+ {{ message.uid_interested.last_name2 | titlecase }}
+ </h5>
+ <div class="box bg-light-inverse" *ngIf="i === 0; else answer;">
+ {{ text[message.uid_interested.uid] }} <br>
+ Libro: {{ message.book.title }} <br>
+ Transacción: {{ message.transaction }} <br>
+ <span *ngIf="message.transaction === 'Venta'">Valor: {{ message.price }} <br></span>
+ Lugar y horario: {{ message.pref }} <br>
+ </div>
+ <ng-template #answer>
+ <div class="box bg-light-info">
+ {{ text[message.uid_interested.uid] }} </div>
+ </ng-template>
+ </div>
+ <div class="chat-img">
+ <img [src]="message.uid_interested.img" class="img-circle-40"/>
+ </div>
+ </div>
+ </li>
+
+ <!-- IZQUIERDA -->
+ <li>
+ <!-- INTERESADO -->
+ <div *ngIf="message.uid_interested.uid !== uid && text[message.uid_interested.uid] !== undefined">
+ <div class="chat-img">
+ <img [src]="message.uid_interested.img" class="img-circle-40"/>
+ </div>
+ <div class="chat-content">
+ <h5>
+ {{ message.uid_interested.name | titlecase }}
+ {{ message.uid_interested.last_name1 | titlecase }}
+ {{ message.uid_interested.last_name2 | titlecase }}
+ </h5>
+ <div class="box bg-light-info" *ngIf="i === 0; else answer;">
+ {{ text[message.uid_interested.uid] }} <br>
+ Libro: {{ message.book.title }} <br>
+ Transacción: {{ message.transaction }} <br>
+ <span *ngIf="message.transaction === 'Venta'">Valor: {{ message.price }} <br></span>
+ Lugar y horario: {{ message.pref }} <br>
+ </div>
+ <ng-template #answer>
+ <div class="box bg-light-info">
+ {{ text[message.uid_interested.uid] }} </div>
+ </ng-template>
+ </div>
+ <div class="chat-time">{{ message.date }}</div>
+ </div>
+
+ <!-- DUEÑO -->
+ <div *ngIf="message.user_owner !== uid && text[message.user_owner] !== undefined">
+ <div class="chat-img">
+ <img [src]="message.book.user.img" class="img-circle-40"/>
+ </div>
+ <div class="chat-content">
+ <h5>
+ {{ message.book.user.name | titlecase }}
+ {{ message.book.user.last_name1 | titlecase }}
+ {{ message.book.user.last_name2 | titlecase }}
+ </h5>
+ <div class="box bg-light-info">{{ text[message.user_owner] }} </div>
+ </div>
+ <div class="chat-time">{{ message.date }}</div>
+ </div>
+ </li>
+ </div>
+ </ul>
+ </div>
+ <div class="card-body b-t" *ngIf="key !== undefined;">
+ <div class="row">
+ <div class="col-8">
+ <textarea [(ngModel)]="text_answer" name="text_answer" placeholder="Escribe tu respuesta aquí..." class="form-control b-0"></textarea>
+ </div>
+ <div class="col-4 text-right">
+ <button type="button" class="btn btn-info btn-circle btn-lg" (click)="sendMessage(message, text_answer)">
+ <i class="fa fa-paper-plane-o"></i>
+ </button>
+ <!-- FIXME: Terminar -->
+ <button type="button" class="btn btn-success btn-circle btn-lg" (click)="transactionDone()" title="Confirmar que hay un acuerdo de transacción">
+ <i class="fa fa-check"></i>
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- =============================================================== -->
+ <!-- End right panel -->
+ <!-- =============================================================== -->
+ </div>
+ </div>
+ </div>
+<div>
+<!-- ============================================================== -->
+<!-- End PAge Content -->
+<!-- ============================================================== -->
+
+
+<ng-template #elseChat>
+ <br><br><br><br><br>
+ <div class="alert alert-primary" role="alert">
+ Debe seleccionar un mensaje...
+ </div>
+</ng-template>
+
+ ./chats.component.css
+
/*
+Template Name: Admin pro Admin
+Author: Wrappixel
+Email: niravjoshi87@gmail.com
+File: scss
+*/
+/*
+Template Name: Admin Pro Admin
+Author: Wrappixel
+Email: niravjoshi87@gmail.com
+File: scss
+*/
+/*Theme Colors*/
+/*bootstrap Color*/
+/*Light colors*/
+/*Normal Color*/
+/*Extra Variable*/
+/*******************
+chat application Page
+******************/
+.chat-main-box {
+ position: relative;
+ overflow: hidden; }
+ .chat-main-box .chat-left-aside {
+ position: relative;
+ width: 250px;
+ float: left;
+ z-index: 9;
+ top: 0px;
+ border-right: 1px solid rgba(120, 130, 140, 0.13); }
+ .chat-main-box .chat-left-aside .open-panel {
+ display: none;
+ cursor: pointer;
+ position: absolute;
+ left: -webkit-calc(100% - 1px);
+ top: 50%;
+ z-index: 100;
+ background-color: #fff;
+ -webkit-box-shadow: 1px 0 3px rgba(0, 0, 0, 0.2);
+ box-shadow: 1px 0 3px rgba(0, 0, 0, 0.2);
+ border-radius: 0 100px 100px 0;
+ line-height: 1;
+ padding: 15px 8px 15px 4px; }
+ .chat-main-box .chat-left-aside .chat-left-inner {
+ position: relative; }
+ .chat-main-box .chat-left-aside .chat-left-inner .chatonline {
+ position: relative;
+ height: 90%; }
+ .chat-main-box .chat-left-aside .chat-left-inner .form-control {
+ height: 60px;
+ padding: 15px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#398bf7), to(#398bf7)), -webkit-gradient(linear, left top, left bottom, from(rgba(120, 130, 140, 0.13)), to(rgba(120, 130, 140, 0.13)));
+ background-image: -webkit-linear-gradient(#398bf7, #398bf7), -webkit-linear-gradient(rgba(120, 130, 140, 0.13), rgba(120, 130, 140, 0.13));
+ background-image: -o-linear-gradient(#398bf7, #398bf7), -o-linear-gradient(rgba(120, 130, 140, 0.13), rgba(120, 130, 140, 0.13));
+ background-image: linear-gradient(#398bf7, #398bf7), linear-gradient(rgba(120, 130, 140, 0.13), rgba(120, 130, 140, 0.13)); }
+ .chat-main-box .chat-left-aside .chat-left-inner .style-none {
+ padding: 0px; }
+ .chat-main-box .chat-left-aside .chat-left-inner .style-none li {
+ list-style: none;
+ overflow: hidden; }
+ .chat-main-box .chat-left-aside .chat-left-inner .style-none li a {
+ padding: 20px; }
+ .chat-main-box .chat-left-aside .chat-left-inner .style-none li a:hover, .chat-main-box .chat-left-aside .chat-left-inner .style-none li a.active {
+ background: #ebf3f5; }
+ .chat-main-box .chat-right-aside {
+ width: calc(100% - 250px);
+ float: left; }
+ .chat-main-box .chat-right-aside .chat-rbox {
+ height: auto;
+ position: relative; }
+ .chat-main-box .chat-right-aside .chat-list {
+ max-height: none;
+ height: 100%;
+ padding-top: 40px; }
+ .chat-main-box .chat-right-aside .chat-list .chat-text {
+ border-radius: 6px; }
+ .chat-main-box .chat-right-aside .send-chat-box {
+ position: relative; }
+ .chat-main-box .chat-right-aside .send-chat-box .form-control {
+ border: none;
+ border-top: 1px solid rgba(120, 130, 140, 0.13);
+ resize: none;
+ height: 80px;
+ padding-right: 180px; }
+ .chat-main-box .chat-right-aside .send-chat-box .form-control:focus {
+ border-color: rgba(120, 130, 140, 0.13); }
+ .chat-main-box .chat-right-aside .send-chat-box .custom-send {
+ position: absolute;
+ right: 20px;
+ bottom: 10px; }
+ .chat-main-box .chat-right-aside .send-chat-box .custom-send .cst-icon {
+ color: #67757c;
+ margin-right: 10px; }
+
+ +
+ src/app/admin/dashboard/dashboard.component.ts
+
+
+ OnInit
+
selector | +app-dashboard |
+
styleUrls | +./dashboard.component.css |
+
templateUrl | +./dashboard.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, _date: DateService)
+ |
+ |||||||||
+ + | +|||||||||
+
+ Parameters :
+
+
|
+
+ + + + addTask + + + + | +
+addTask()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + searchReportDate + + + + | +||||
+searchReportDate(date)
+ |
+ ||||
+ + | +||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + actual_date + + + + | +
+ actual_date:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + actual_day + + + + | +
+ actual_day:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + actual_user + + + + | +
+ actual_user:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + count_books + + + + | +
+ count_books:
+ |
+
+ Type : number
+
+ |
+
+ + | +
+ + + + count_messages + + + + | +
+ count_messages:
+ |
+
+ Type : number
+
+ |
+
+ + | +
+ + + + count_users + + + + | +
+ count_users:
+ |
+
+ Type : number
+
+ |
+
+ + | +
+ + + + date + + + + | +
+ date:
+ |
+
+ Type : string
+
+ |
+
+ + | +
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : FormGroup
+
+ |
+
+ + | +
+ + + + reports + + + + | +
+ reports:
+ |
+
+ Type : any[]
+
+ |
+
+ + | +
+ + + + reportsData + + + + | +
+ reportsData:
+ |
+
+ Type : any[]
+
+ |
+
+ + | +
+ + + + tasks + + + + | +
+ tasks:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + users + + + + | +
+ users:
+ |
+
+ Type : any
+
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { FormControl, FormControlName, FormGroup, Validators } from '@angular/forms';
+
+// SERVICES
+import { DatabaseService } from '../../services/database.service';
+import { DateService } from '../../services/date.service';
+
+@Component({
+ selector: 'app-dashboard',
+ templateUrl: './dashboard.component.html',
+ styleUrls: ['./dashboard.component.css']
+})
+export class DashboardComponent implements OnInit {
+
+ actual_user:any;
+ actual_date:any;
+ actual_day:any;
+
+ // Data de la DB
+ users:any;
+ reports:any[];
+ reportsData:any[];
+ tasks:any;
+
+ // Cantidad de
+ count_users:number;
+ count_books:number;
+ count_messages:number;
+
+ // Inputs
+ date:string;
+
+ form:FormGroup;
+
+ constructor( private _dbService:DatabaseService,
+ private _date:DateService ) {
+ this.actual_user = JSON.parse( localStorage.getItem( "user" ) );
+ this.actual_date = this._date.actual_date();
+ this.actual_day = this._date.actual_day();
+
+ this._dbService.getData( "users")
+ .valueChanges()
+ .subscribe( (data:any) => {
+ this.users = data;
+ this.count_users = data.length;
+ });
+
+ this._dbService.getData( "books")
+ .valueChanges()
+ .subscribe( data => this.count_books = data.length );
+
+ this._dbService.getData( "messages-transaction")
+ .valueChanges()
+ .subscribe( data => this.count_messages = data.length );
+
+ this._dbService.getData( "reports")
+ .valueChanges()
+ .subscribe( data => {
+ this.reports = data;
+ this.reportsData = this.reports;
+ });
+
+ // this._dbService.getData( "tasks")
+ // .valueChanges()
+ // .subscribe( data => this.tasks = data );
+
+
+ }
+
+ ngOnInit() {
+ this.form = new FormGroup({
+ task: new FormControl(undefined, Validators.required),
+ description: new FormControl(undefined, Validators.required),
+ priority: new FormControl(undefined, Validators.required) //high, medium, low
+ });
+ }
+
+ // TODO: Terminar po jjj
+ // FIXME: Terminar o sacar
+ addTask(){
+ this._dbService.addDataIdCustom('tasks', this.actual_user, this.form)
+ .then( () => swal('Tarea guardada', 'La tarea ha sido guardada con éxito', 'success') )
+ .catch( () => swal('Error', 'La tarea no ha podido guardarse, vuelva a intentarlo', 'error') );
+ }
+
+ searchReportDate(date){
+ this.reports = [];
+ if( date === 'all' ){
+ this.reports = this.reportsData;
+ }else {
+ for(let r of this.reportsData) {
+ if( r.day === date ) this.reports.push(r);
+ }
+ }
+ }
+
+
+}
+
+ <div class="container-dashboard">
+ <!-- =============================================================== -->
+ <!-- Report boxes -->
+ <!-- =============================================================== -->
+ <div class="row">
+ <div class="col-lg-4">
+ <div class="card">
+ <div class="card-body">
+ <div class="d-flex no-block">
+ <div class="m-r-20 align-self-center">
+ <span class="lstick m-r-20"></span>
+ <img src="../assets/images/icon/staff.png" alt="Income" />
+ </div>
+ <div class="align-self-center">
+ <h6 class="text-muted m-t-10 m-b-0">Total de usuarios</h6>
+ <h2 class="m-t-0">{{ count_users }}</h2>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-lg-4">
+ <div class="card">
+ <div class="card-body">
+ <div class="d-flex no-block">
+ <div class="m-r-20 align-self-center">
+ <span class="lstick m-r-20"></span>
+ <img src="../assets/images/icon/expense.png" alt="Income" />
+ </div>
+ <div class="align-self-center">
+ <h6 class="text-muted m-t-10 m-b-0">Total de libros</h6>
+ <h2 class="m-t-0">{{ count_books }}</h2>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-lg-4">
+ <div class="card">
+ <div class="card-body">
+ <div class="d-flex no-block">
+ <div class="m-r-20 align-self-center">
+ <span class="lstick m-r-20"></span>
+ <img src="../assets/images/icon/assets.png" alt="Income" />
+ </div>
+ <div class="align-self-center">
+ <h6 class="text-muted m-t-10 m-b-0">Mensajes enviados</h6>
+ <h2 class="m-t-0">{{ count_messages }}</h2>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- =============================================================== -->
+ <!-- End report boxes -->
+ <!-- =============================================================== -->
+
+ <!-- =============================================================== -->
+ <!-- Users status -->
+ <!-- =============================================================== -->
+ <div class="row">
+ <div class="col-lg-12 col-md-12">
+ <div class="card">
+ <div class="card-body">
+ <div class="d-flex">
+ <div>
+ <h4 class="card-title"><span class="lstick"></span>Estado de usuarios</h4>
+ </div>
+ </div>
+ <div class="table-responsive m-t-20">
+ <table class="table vm no-th-brd no-wrap pro-of-month">
+ <thead>
+ <tr>
+ <th colspan="2">Usuario</th>
+ <th>Tipo de usuario</th>
+ <th>Estado</th>
+ <th>Cambiar estado</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let u of users">
+ <td style="width:50px;"><span class="round">
+ <img src="../assets/images/users/1.jpg" alt="user" width="50"></span>
+ </td>
+ <td>
+ <h6>{{ u.name | titlecase }} {{ u.last_name1 | titlecase }} {{ u.last_name2 | titlecase }}</h6>
+ <small class="text-muted">Creado el: {{ u.created_date }}</small>
+ </td>
+ <td>{{ u.role | titlecase }}</td>
+ <td>
+ <span *ngIf="[u.status] == 'true'" class="label label-success label-rounded">Activo</span>
+ <span *ngIf="[u.status] == 'false'" class="label label-danger label-rounded">Inactivo</span>
+ </td>
+ <!-- TODO: Hacer algo con esto -->
+ <td>
+ Cambiar jjj
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- =============================================================== -->
+ <!-- End users status -->
+ <!-- =============================================================== -->
+
+
+ <!-- ============================================================== -->
+ <!-- Reports -->
+ <!-- ============================================================== -->
+ <div class="row">
+ <div class="col-lg-12 col-md-12">
+ <div class="card">
+ <div class="card-body">
+ <div class="d-flex">
+ <div>
+ <h3 class="card-title m-b-5">
+ <span class="lstick"></span>Reportes
+ </h3>
+ </div>
+ <div class="ml-auto">
+ <label>Fecha</label>
+ <select class="custom-select b-0" [(ngModel)]="date" name="date" (ngModelChange)="searchReportDate($event)">Fecha
+ <option value="all" selected>Todas</option>
+ <option *ngFor="let r of reportsData">{{ r.day }}</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <table class="table vm no-th-brd no-wrap pro-of-month">
+ <thead>
+ <tr>
+ <th>Usuario que reporta</th>
+ <th>Tipo de reporte</th>
+ <th>Fecha</th>
+ <th>Hora</th>
+ <th>Reporte</th>
+ <th>Estado</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let r of reports">
+ <!-- TODO: Revisar visualmente y borrar referencis sin ID -->
+ <td>
+ <h6>{{ r.user.name | titlecase }} {{ r.user.last_name1 | titlecase }} {{ r.user.last_name2 | titlecase }}</h6>
+ </td>
+ <td>
+ <h6>{{ r.type }}</h6>
+ </td>
+ <td>
+ <h6>{{ r.day }}</h6>
+ </td>
+ <td>
+ <h6>{{ r.hour }}</h6>
+ </td>
+ <td>
+ <h6 *ngIf="r.type == 'Reporte de imagen'">Se reportan las imagenes contenidas en el siguiente <a [href]="r.img" target="_blank"> link </a> </h6>
+ <h6 *ngIf="r.type == 'Reporte de usuario'">Se reporta al usuario {{ r.user_reported.name | titlecase }} {{ r.user_reported.last_name1 | titlecase }} {{ r.user_reported.last_name2 | titlecase }}</h6>
+ </td>
+ <td>
+ <span *ngIf="[r.status] == 'Revisado'" class="label label-success label-rounded">Revisado</span>
+ <span *ngIf="[r.status] == 'No revisado'" class="label label-danger label-rounded">No revisado</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================== -->
+ <!-- End reports -->
+ <!-- ============================================================== -->
+
+ <div class="row">
+ <!-- ============================================================== -->
+ <!-- Todo list -->
+ <!-- ============================================================== -->
+ <div class="col-lg-6 col-xlg-8">
+ <div class="card">
+ <div class="card-body">
+ <div class="d-flex">
+ <div>
+ <h4 class="card-title"><span class="lstick"></span>To Do list</h4>
+ </div>
+ <div class="ml-auto">
+ <button class="pull-right btn btn-circle btn-success" data-toggle="modal" data-target="#myModal">
+ <i class="ti-plus"></i>
+ </button>
+ </div>
+ </div>
+
+ <div class="to-do-widget m-t-20">
+ <!-- ============================================================== -->
+ <!-- Modal for add tasks -->
+ <!-- ============================================================== -->
+ <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-hidden="true">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title">Agregar tarea</h4>
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button>
+ </div>
+ <div class="modal-body">
+ <form [formGroup]="form" (ngSubmit)="addTask()" novalidate>
+ <div class="form-group">
+ <label>Nombre de la tarea</label>
+ <input formControlName="task" type="text" class="form-control" placeholder="Revisar mensajes">
+ </div>
+ <div class="form-group">
+ <label>Descripción de la tarea</label>
+ <input formControlName="description" type="text" class="form-control" placeholder="Revisar la lista de mensajes que están pendientes">
+ </div>
+ <div class="form-group">
+ <label>Prioridad</label>
+ <select formControlName="priority" class="custom-select form-control pull-right">
+ <option value="high">Alta</option>
+ <option value="medium">Media</option>
+ <option value="low">Baja</option>
+ </select>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-success">Agregar</button>
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================== -->
+ <!-- End modal for add tasks -->
+ <!-- ============================================================== -->
+ <ul class="list-task todo-list list-group m-b-0" data-role="tasklist">
+ <!-- <li class="list-group-item" data-role="task" *ngFor="let t of tasks"> -->
+ <div class="checkbox checkbox-info m-b-10">
+ <input type="checkbox" id="inputSchedule" name="inputCheckboxesSchedule">
+ <label for="inputSchedule" class="">
+ <!-- <span>{{ t.task }}</span> -->
+ <!-- <span class="label label-rounded label-danger pull-right">{{ t.description }}</span> -->
+ </label>
+ </div>
+ <!-- </li> -->
+ <li class="list-group-item" data-role="task">
+ <div class="checkbox checkbox-info">
+ <input type="checkbox" id="inputBook" name="inputCheckboxesBook">
+ <label for="inputBook" class="">
+ <span>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been</span>
+ <!-- <span class="label label-primary label-rounded pull-right">{{ t.priority }}</span> -->
+ </label>
+ </div>
+ <div class="item-date"> 26 jun 2017</div>
+ </li>
+ <li class="list-group-item" data-role="task">
+ <div class="checkbox checkbox-info">
+ <input type="checkbox" id="inputCall" name="inputCheckboxesCall">
+ <label for="inputCall" class="">
+ <span>Give Purchase report to</span>
+ <span class="label label-info label-rounded pull-right">Yesterday</span>
+ </label>
+ </div>
+ </li>
+ <li class="list-group-item" data-role="task">
+ <div class="checkbox checkbox-info">
+ <input type="checkbox" id="inputForward" name="inputCheckboxesForward">
+ <label for="inputForward" class="">
+ <span>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been</span>
+ <span class="label label-warning label-rounded pull-right">2 weeks</span>
+ </label>
+ </div>
+ <div class="item-date">{{ actual_day }}</div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================== -->
+ <!-- End todo list -->
+ <!-- ============================================================== -->
+ </div>
+</div>
+<!-- ============================================================== -->
+<!-- End Container fluid -->
+<!-- ============================================================== -->
+
+
+ ./dashboard.component.css
+
+ +
+ src/app/admin/global-message/global-message.component.ts
+
+
+ OnInit
+
selector | +app-global-message |
+
styleUrls | +./global-message.component.css |
+
templateUrl | +./global-message.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_date: DateService, _dbService: DatabaseService)
+ |
+ |||||||||
+ + | +|||||||||
+
+ Parameters :
+
+
|
+
+ + + + moveToDiscart + + + + | +
+moveToDiscart()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + sendMessage + + + + | +
+sendMessage()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + showMessages + + + + | +
+showMessages()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + active_users + + + + | +
+ active_users:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + actual_user + + + + | +
+ actual_user:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + inactive_users + + + + | +
+ inactive_users:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + options + + + + | +
+ options:
+ |
+
+ Type : string
+
+ |
+
+ Default value : 'new_message'
+ |
+
+ + | +
+ + + + reported_users + + + + | +
+ reported_users:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + reports + + + + | +
+ reports:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + users + + + + | +
+ users:
+ |
+
+ Type : any
+
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+
+// SERVICES
+import { DateService } from '../../services/date.service';
+import { DatabaseService } from '../../services/database.service';
+
+@Component({
+ selector: 'app-global-message',
+ templateUrl: './global-message.component.html',
+ styleUrls: ['./global-message.component.css']
+})
+export class GlobalMessageComponent implements OnInit {
+
+ form:any;
+ actual_user:any;
+
+ // Traen las colecciones
+ users:any;
+ reports:any;
+
+ // Arreglos de usuarios para enviar mensajes globales
+ active_users:any = [];
+ inactive_users:any = [];
+ reported_users:any = [];
+
+ options:string = 'new_message'; // Controla las opciones que se muestran en la columna derecha
+
+
+ constructor(private _date:DateService,
+ private _dbService:DatabaseService) {
+
+ this.actual_user = JSON.parse(localStorage.getItem('user'));
+
+ this._dbService.getDataQuery( "users", "status", "==", true)
+ .valueChanges()
+ .subscribe( data => {
+ this.active_users = data;
+ });
+
+ this._dbService.getDataQuery( "users", "status", "==", false)
+ .valueChanges()
+ .subscribe( data => {
+ this.inactive_users = data;
+ });
+
+ this._dbService.getDataQuery("reports", "type", "==", "Reporte de usuario")
+ .valueChanges()
+ .subscribe( (data:any) => {
+ this.reported_users = [];
+ for(let r of data){
+ this.reported_users.push(r.user_reported);
+ }
+ });
+
+ this._dbService.getData( "reports")
+ .valueChanges()
+ .subscribe( data => {
+ this.reports = data;
+ });
+ }
+
+ ngOnInit() {
+
+ this.form = new FormGroup({
+ receiver: new FormControl(undefined, Validators.required),
+ title: new FormControl(undefined, Validators.required),
+ body: new FormControl(undefined, Validators.required),
+ })
+
+ }
+
+ sendMessage(){
+ let message = {
+ receiver: '',
+ title: this.form.value.title,
+ body: this.form.value.body,
+ day: this._date.actual_day(),
+ hour: this._date.actual_hour(),
+ status: false
+ }
+
+ switch (this.form.value.receiver) {
+ case 'Usuarios activos':
+ message.receiver = this.active_users;
+ break;
+ case 'Usuarios no activos':
+ message.receiver = this.inactive_users;
+ break;
+ case 'Usuarios reportados':
+ message.receiver = this.reported_users;
+ break;
+ default:
+ break;
+ }
+
+ // Envía el mensaje a la DB.
+ this._dbService.addData('global-messages', message)
+ .then( () => swal('Mensaje enviado', 'El mensaje ha sido enviado con éxito', 'success') )
+ .catch( () => swal('Error', 'El mensaje no ha podido enviarse, vuelva a intentarlo', 'error') );
+ }
+
+ moveToDiscart(){
+
+ }
+
+ showMessages(){
+
+ }
+
+}
+
+ <div class="row">
+ <div class="col-lg-12">
+ <div class="card">
+ <div class="row">
+ <!-- ============================================================== -->
+ <!-- Left column -->
+ <!-- ============================================================== -->
+ <div class="col-xlg-2 col-lg-3 col-md-4 ">
+ <div class="card-body inbox-panel">
+ <a href="app-compose.html" class="btn btn-danger m-b-20 p-10 btn-block waves-effect waves-light">Compose</a>
+ <ul class="list-group list-group-full">
+ <li class="list-group-item active">
+ <a href="javascript:void(0)"><i class="mdi mdi-gmail"></i> Bandeja de entrada </a>
+ <span class="badge badge-success ml-auto">6</span></li>
+ <li class="list-group-item">
+ <a href="javascript:void(0)"><i class="mdi mdi-star"></i> Favoritos </a>
+ </li>
+ <li class="list-group-item ">
+ <a href="javascript:void(0)"><i class="mdi mdi-file-document-box"></i> Reportes </a>
+ </li>
+ <li class="list-group-item">
+ <a href="javascript:void(0)"><i class="mdi mdi-delete"></i> Descartados </a>
+ </li>
+ </ul>
+ <h3 class="card-title m-t-40">Etiquetas</h3>
+ <div class="list-group b-0 mail-list">
+ <div href="#" class="list-group-item"><span class="fa fa-circle text-success m-r-10"></span>Usuarios activos</div>
+ <div href="#" class="list-group-item"><span class="fa fa-circle text-warning m-r-10"></span>Usuarios no activos</div>
+ <div href="#" class="list-group-item"><span class="fa fa-circle text-danger m-r-10"></span>Usuarios reportados</div>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================== -->
+ <!-- End left column -->
+ <!-- ============================================================== -->
+
+ <!-- TODO: Revisar si esta huea quedó guena -->
+ <div class="col-xlg-10 col-lg-9 col-md-8 bg-light-part b-l" [ngSwitch]="options">
+ <!-- ============================================================== -->
+ <!-- New message right column -->
+ <!-- ============================================================== -->
+ <div class="card-body" *ngSwitchCase="'new_message'">
+ <h3 class="card-title">Nuevo mensaje</h3>
+ <form [formGroup]="form" (ngSubmit)="sendMessage()">
+ <div class="row">
+ <div class="form-group col-12">
+ <label class="col-2">Para:</label>
+ <select class="form-control col-10" formControlName="receiver">
+ <option value="Usuarios activos">Usuarios activos</option>
+ <option value="Usuarios no activos">Usuarios no activos</option>
+ <option value="Usuarios reportados">Usuarios reportados</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <input class="form-control" placeholder="Título:" formControlName="title">
+ </div>
+
+ <div class="form-group">
+ <textarea class="textarea_editor form-control" rows="15" placeholder="Cuerpo del mensaje..." style="height: 250px;"
+ formControlName="body"></textarea>
+ </div>
+
+ <button type="submit" class="btn btn-info m-t-20"><i class="fa fa-envelope-o"></i> Enviar</button>
+ <button class="btn btn-danger m-t-20"><i class="fa fa-times" (click)="moveToDiscart()"></i> Descartar</button>
+ </form>
+ </div>
+ <!-- ============================================================== -->
+ <!-- End new message right column -->
+ <!-- ============================================================== -->
+
+ <!-- ============================================================== -->
+ <!-- Reports messages right column -->
+ <!-- ============================================================== -->
+ <!-- FIXME: -->
+ <div class="chat-left-inner" *ngSwitchCase="'report_messages'">
+ <div class="form-material">
+ <input class="form-control p-20" type="text" placeholder="Buscar Chat">
+ </div>
+ <ul class="chatonline style-none">
+ <!-- <li *ngFor="let c of chats | async" (click)="showMessages(c.key)"> -->
+ <li *ngFor="let r of reports | async">
+ <a >
+ <img [src]="r.user.img" alt="user-img" class="img-circle img-circle-30">
+ <span>
+ {{ r.user.name | titlecase }}
+ <small class="text-muted">{{ r.type }}</small>
+ </span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ <!-- ============================================================== -->
+ <!-- Reports messages right column -->
+ <!-- ============================================================== -->
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+
+
+
+ ./global-message.component.css
+
+ +
+ src/app/shared/header/header.component.ts
+
+
+ OnInit
+
selector | +app-header |
+
styleUrls | +./header.component.css |
+
templateUrl | +./header.component.html |
+
+ Properties+ |
+
+ + | +
+ Methods+ |
+
+
|
+
+constructor(router: Router, auth: AngularFireAuth, _dbService: DatabaseService)
+ |
+ ||||||||||||
+ Defined in src/app/shared/header/header.component.ts:22
+ |
+ ||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + logout + + + + | +
+logout()
+ |
+
+ Defined in src/app/shared/header/header.component.ts:54
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/shared/header/header.component.ts:44
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + resetProfile + + + + | +
+resetProfile()
+ |
+
+ Defined in src/app/shared/header/header.component.ts:71
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + searchBook + + + + | +||||||
+searchBook(input: string)
+ |
+ ||||||
+ Defined in src/app/shared/header/header.component.ts:49
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + loading + + + + | +
+ loading:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : true
+ |
+
+ Defined in src/app/shared/header/header.component.ts:22
+ |
+
+ + + + profile + + + + | +
+ profile:
+ |
+
+ Type : any
+
+ |
+
+ Defined in src/app/shared/header/header.component.ts:21
+ |
+
import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { map } from 'rxjs/operators';
+
+// ANGULARFIRE2
+import { AngularFireAuth } from 'angularfire2/auth';
+
+// SERVICE
+import { DatabaseService } from "../../services/database.service";
+
+// PLUGINS
+import swal from 'sweetalert';
+
+@Component({
+ selector: 'app-header',
+ templateUrl: './header.component.html',
+ styleUrls: ['./header.component.css']
+})
+export class HeaderComponent implements OnInit {
+
+ profile:any;
+ loading:boolean = true;
+
+ constructor( private router:Router,
+ private auth: AngularFireAuth,
+ private _dbService:DatabaseService ) {
+ let actual_user = JSON.parse( localStorage.getItem( "user" ) );
+
+ this._dbService.getDataQuery( "users", "uid", "==", actual_user.uid)
+ .snapshotChanges()
+ .pipe(
+ map(actions => actions.map(a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+ return { key, ...data };
+ }))
+ ).subscribe( data => {
+ this.profile = [];
+ this.profile = data[0];
+ this.loading = false;
+ });
+ }
+
+ ngOnInit() {
+ this.resetProfile();
+ }
+
+ // Busca un libro según el texto de entrada
+ searchBook( input:string ){
+ this.router.navigate(['/search', input]);
+ }
+
+ // Cierra la sesión del usuario actual
+ logout(){
+ this.auth.auth.signOut()
+ .then( () => {
+ localStorage.removeItem('user');
+
+ let rememberMe = JSON.parse(localStorage.getItem('session')).rememberMe;
+ localStorage.setItem('session', JSON.stringify({
+ session: false,
+ rememberMe: rememberMe
+ }));
+
+ swal('Adiós', 'Vuelva pronto', 'success');
+ this.router.navigate(['/login']);
+ })
+ .catch( ()=> swal('Error al cerrar sesión', 'Vuelva a intentarlo', 'error') );
+ }
+
+ resetProfile(){
+ this.profile = {
+ uid: '',
+ rut: '',
+ name: '',
+ last_name1: '',
+ last_name2: '',
+ email: [],
+ phone: '',
+ ranking: 0,
+ favs_genres: [],
+ commune: ''
+ };
+ }
+
+}
+
+ <header class="topbar">
+ <nav class="navbar top-navbar navbar-expand-md navbar-light">
+ <!-- ============================================================== -->
+ <!-- Logo -->
+ <!-- ============================================================== -->
+ <div class="navbar-header">
+ <a class="navbar-brand" [routerLink]="['/home']">
+ <b>
+ <!-- Logo icon -->
+ <img src="assets/images/logo-icon.png" style="max-width: 60px; max-height: 60px" alt="homepage" class="dark-logo" />
+ </b>
+ <span>
+ <!-- Logo text -->
+ <img src="assets/images/logo-text.png" alt="homepage" class="dark-logo" />
+ </span>
+ </a>
+ </div>
+ <!-- ============================================================== -->
+ <!-- End Logo -->
+ <!-- ============================================================== -->
+ <div class="navbar-collapse">
+ <!-- ============================================================== -->
+ <!-- Toggle and nav items -->
+ <!-- ============================================================== -->
+ <ul class="navbar-nav mr-auto">
+ <!-- This is -->
+ <li class="nav-item">
+ <a class="nav-link nav-toggler hidden-md-up waves-effect waves-dark" href="javascript:void(0)">
+ <i class="ti-menu"></i>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link sidebartoggler hidden-sm-down waves-effect waves-dark" href="javascript:void(0)">
+ <i class="ti-menu"></i>
+ </a>
+ </li>
+ <li class="nav-item"></li>
+ </ul>
+ <!-- ============================================================== -->
+ <!-- User profile, notifications, add book and search -->
+ <!-- ============================================================== -->
+ <ul class="navbar-nav my-lg-0">
+ <!-- ============================================================== -->
+ <!-- Search -->
+ <!-- ============================================================== -->
+ <li class="nav-item search-box">
+ <a class="nav-link waves-effect waves-dark" href="javascript:void(0)">
+ <i class="ti-search"></i>
+ </a>
+ <div class="app-search">
+ <input type="text" class="form-control" placeholder="Buscar..." (keyup.enter)="searchBook(Search.value)" #Search>
+ <a class="srh-btn" >
+ <i class="ti-close"></i>
+ </a>
+ </div>
+ </li>
+ <!-- ============================================================== -->
+ <!-- End search -->
+ <!-- ============================================================== -->
+
+ <!-- ============================================================== -->
+ <!-- Notifications -->
+ <!-- ============================================================== -->
+ <li class="nav-item dropdown">
+ <a class="nav-link dropdown-toggle waves-effect waves-dark" href="" data-toggle="dropdown"
+ aria-haspopup="true" aria-expanded="false">
+ <i class="mdi mdi-message"></i>
+ <div class="notify">
+ <span class="point"></span>
+ </div>
+ </a>
+ <app-notifications></app-notifications>
+
+ </li>
+ <!-- ============================================================== -->
+ <!-- End Notifications -->
+ <!-- ============================================================== -->
+
+ <!-- ============================================================== -->
+ <!-- Messages -->
+ <!-- ============================================================== -->
+ <li class="nav-item dropdown">
+ <a aria-expanded="false" aria-haspopup="true" class="nav-link dropdown-toggle waves-effect waves-dark"
+ data-toggle="dropdown" href="" id="2">
+ <i class="mdi mdi-email"></i>
+ <div class="notify">
+ <span class="point"></span>
+ </div>
+ </a>
+ <app-messages></app-messages>
+ </li>
+ <!-- ============================================================== -->
+ <!-- End messages -->
+ <!-- ============================================================== -->
+
+ <!-- ============================================================== -->
+ <!-- Add book -->
+ <!-- ============================================================== -->
+ <li class="nav-item">
+ <a [routerLink]="['/addBook']" class="nav-link waves-effect waves-dark">
+ <img src="assets/images/add.png" alt="add_book" style="width: 25px;" />
+ </a>
+
+ </li>
+ <!-- ============================================================== -->
+ <!-- End Add book -->
+ <!-- ============================================================== -->
+
+ <!-- ============================================================== -->
+ <!-- Profile -->
+ <!-- ============================================================== -->
+ <li class="nav-item dropdown">
+ <a aria-expanded="false" aria-haspopup="true" class="nav-link dropdown-toggle waves-effect waves-dark"
+ data-toggle="dropdown" href="">
+ <img [src]="profile.img" alt="user" class="img-circle-50" *ngIf="!loading; else loadingElse"/>
+ <ng-template #loadingElse>
+ <app-loading></app-loading>
+ </ng-template>
+ </a>
+ <div class="dropdown-menu dropdown-menu-right mailbox animated bounceInDown chaoOverflow">
+ <ul class="dropdown-user">
+ <li>
+ <div class="dw-user-box">
+ <div class="u-img">
+ <img [src]="profile.img" alt="user">
+ </div>
+ <div class="u-text">
+ <h4>{{ profile.name | titlecase }} {{ profile.last_name1 | titlecase }} {{ profile.last_name2 | titlecase }}</h4>
+ <p class="text-muted">{{ profile.email }}</p>
+ <a [routerLink]="['/profile']"
+ class="btn btn-rounded btn-danger btn-sm">
+ Ver perfil
+ </a>
+ </div>
+ </div>
+ </li>
+ <li role="separator" class="divider"></li>
+ <li>
+ <a [routerLink]="['/profile']">
+ <i class="ti-user"></i> Mi perfil
+ </a>
+ </li>
+ <li>
+ <a [routerLink]="['/library']">
+ <i class="ti-wallet"></i> Mi biblioteca
+ </a>
+ </li>
+ <li>
+ <a [routerLink]="['/messages']">
+ <i class="ti-email"></i> Mis mensajes
+ </a>
+ </li>
+ <li role="separator" class="divider"></li>
+ <li>
+ <a (click)="logout()">
+ <i class="fa fa-power-off"></i> Cerrar sesión
+ </a>
+ </li>
+ </ul>
+ </div>
+ </li>
+ <!-- ============================================================== -->
+ <!-- End Profile -->
+ <!-- ============================================================== -->
+ </ul>
+ </div>
+ </nav>
+</header>
+
+
+ ./header.component.css
+
+ +
+ src/app/pages/home/home.component.ts
+
+
+ OnInit
+
selector | +app-home |
+
styleUrls | +./home.component.css |
+
templateUrl | +./home.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, route: Router)
+ |
+ |||||||||
+ Defined in src/app/pages/home/home.component.ts:16
+ |
+ |||||||||
+
+ Parameters :
+
+
|
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/pages/home/home.component.ts:51
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + preferencesRoute + + + + | +
+preferencesRoute()
+ |
+
+ Defined in src/app/pages/home/home.component.ts:53
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + books + + + + | +
+ books:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/pages/home/home.component.ts:14
+ |
+
+ + + + firtSession + + + + | +
+ firtSession:
+ |
+
+ Type : null
+
+ |
+
+ Default value : null
+ |
+
+ Defined in src/app/pages/home/home.component.ts:15
+ |
+
+ + + + preferences + + + + | +
+ preferences:
+ |
+
+ Type : null
+
+ |
+
+ Default value : null
+ |
+
+ Defined in src/app/pages/home/home.component.ts:16
+ |
+
+ + + + view_bar + + + + | +
+ view_bar:
+ |
+
+ Type : string
+
+ |
+
+ Default value : 'all'
+ |
+
+ Defined in src/app/pages/home/home.component.ts:13
+ |
+
import { Component, OnInit, Input } from '@angular/core';
+import { DatabaseService } from "../../services/database.service";
+import { Router } from '@angular/router';
+
+
+@Component({
+ selector: 'app-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.css']
+})
+export class HomeComponent implements OnInit {
+
+ view_bar:string = 'all';
+ books:any[] = [];
+ firtSession = null;
+ preferences = null;
+
+ constructor( private _dbService:DatabaseService, private route:Router ) {
+ const UID = JSON.parse(localStorage.getItem('user')).uid;
+
+ this._dbService.getDataQuery('books', 'status', '==', 'available')
+ .valueChanges()
+ .subscribe( data => {
+ this.books = [];
+ this.books = data;
+
+ // Cambia la referencia del user por el objeto del usuario
+ for(let i=0; i<this.books.length; i++){
+ this._dbService.afs.doc(data[i].user)
+ .valueChanges()
+ .subscribe( resp => this.books[i].user = resp );
+ }
+ });
+
+ this._dbService.getDataQuery('users', 'uid', '==', UID)
+ .valueChanges()
+ .subscribe( data => {
+ let user = data[0];
+ if( user.preferences !== undefined && user.preferences !== null )
+ this.preferences = user.preferences.length;
+ else
+ this.preferences = 0;
+
+ if( !user.firtSession ) {
+ user.firtSession = true;
+ this._dbService.updateData('users', UID, user);
+ }
+ });
+ }
+
+ ngOnInit() {}
+
+ preferencesRoute() {
+ this.route.navigate(['/profile', {input: 'preferences'}]);
+ }
+
+}
+
+
+
+<div class="noSession" *ngIf="preferences === 0">
+ <span>
+ Recuerde ingresar sus preferencias
+ <a (click)="preferencesRoute()"> Ingresar preferencias ahora </a>
+ </span>
+ <a class="close" style="cursor: pointer;" (click)="preferences = 1">×</a>
+</div>
+
+
+<!-- ============================================================================== -->
+<!-- Options view bar -->
+<!-- ============================================================================== -->
+<div class="container mb-3">
+ <div class="row text-center">
+ <div class="col-12">
+ <div class="btn-group mr-2" role="group">
+ <button type="button" class="btn btn-secondary"
+ [ngClass]="{'active': view_bar === 'all'}"
+ (click)="view_bar = 'all'">
+ Todos
+ </button>
+ <button type="button" class="btn btn-secondary"
+ [ngClass]="{'active': view_bar === 'exchange'}"
+ (click)="view_bar = 'exchange'">
+ Intercambio
+ </button>
+ <button type="button" class="btn btn-secondary"
+ [ngClass]="{'active': view_bar === 'sales'}"
+ (click)="view_bar = 'sales'">
+ Ventas
+ </button>
+ <button type="button" class="btn btn-secondary"
+ [ngClass]="{'active': view_bar === 'both'}"
+ (click)="view_bar = 'both'">
+ Ambos
+ </button>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- ============================================================================== -->
+<!-- End options view bar -->
+<!-- ============================================================================== -->
+
+<!-- ============================================================================== -->
+<!-- Cards according to view bar -->
+<!-- ============================================================================== -->
+<div [ngSwitch]="view_bar">
+ <div *ngSwitchCase="'all'">
+ <app-card-book type="all" [booksHome]="books"></app-card-book>
+ </div>
+ <div *ngSwitchCase="'exchange'">
+ <app-card-book type="Intercambio" [booksHome]="books"></app-card-book>
+ </div>
+ <div *ngSwitchCase="'sales'">
+ <app-card-book type="Venta" [booksHome]="books"></app-card-book>
+ </div>
+ <div *ngSwitchCase="'both'">
+ <app-card-book type="Ambos" [booksHome]="books"></app-card-book>
+ </div>
+</div>
+<!-- ============================================================================== -->
+<!-- End cards according to view bar -->
+<!-- ============================================================================== -->
+
+
+ ./home.component.css
+
.noSession {
+ width: 98%;
+ padding: 1rem;
+ background: #F2D7D5;
+ margin-bottom: 1rem;
+ display: flex;
+ justify-content: space-between;
+}
+
+.noSession span a {
+ cursor: pointer;
+ color: blue;
+}
+
+.noSession a {
+ cursor: pointer;
+}
+
+
+ +
+ src/app/pages/library/library.component.ts
+
+
+ OnInit
+
selector | +app-library |
+
templateUrl | +./library.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService)
+ |
+ ||||||
+ + | +||||||
+
+ Parameters :
+
+
|
+
+ + + + deleteBook + + + + | +
+deleteBook()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + resetBook + + + + | +
+resetBook()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + updateBook + + + + | +
+updateBook()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + book_modal + + + + | +
+ book_modal:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + books + + + + | +
+ books:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { map } from 'rxjs/operators';
+
+// SERVICE
+import { DatabaseService } from "../../services/database.service";
+
+// SWEET ALERT
+import swal from 'sweetalert';
+
+@Component({
+ selector: 'app-library',
+ templateUrl: './library.component.html'
+})
+export class LibraryComponent implements OnInit {
+
+ books: any[] = [];
+ book_modal: any;
+
+ constructor( private _dbService:DatabaseService ) {
+ let user = JSON.parse( localStorage.getItem( "user" ) );
+
+ this._dbService.getDataQuery( "books", "uid", "==", user.uid)
+ .snapshotChanges()
+ .pipe(
+ map(actions => actions.map(a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+ return { key, ...data };
+ }))
+ ).subscribe( data => {
+ this.books = [];
+ this.books = data;
+ });
+ }
+
+ ngOnInit() {
+ this.resetBook();
+ }
+
+ // Actualiza el libro en la DB
+ updateBook(){
+ this._dbService.updateData( "books", this.book_modal.key, this.book_modal )
+ .then( () => {
+ swal('Cambios guardados', 'Sus cambios han sidos guardados con éxito', 'success');
+ })
+ .catch( () => {
+ swal('Error al editar', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ }
+
+ // Elimina un libro de la DB
+ deleteBook(){
+ this._dbService.deleteData( "books", this.book_modal.key )
+ .then( () => {
+ swal('Libro eliminado', 'El libro seleccionado ha sido eliminado', 'success');
+ this.resetBook();
+ })
+ .catch( () => {
+ swal('Error al eliminar', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ }
+
+ // Deja los campos de libro en blanco al borrar uno o entrar en Mi Biblioteca
+ resetBook(){
+ this.book_modal = {
+ author: '',
+ title: '',
+ editorial: '',
+ type: '',
+ genres: [],
+ language: '',
+ num_page: '',
+ original: false,
+ transaction: '',
+ user: '',
+ id: '',
+ comment: '',
+ price: 0,
+ images: []
+ };
+ }
+
+}
+
+ <div class="container-fluid">
+ <div class="row">
+ <!-- ============================================================================================== -->
+ <!-- Column left: List of books -->
+ <!-- ============================================================================================== -->
+ <div class="col-4">
+ <h3>Mis libros</h3>
+ <ul class="list-group">
+ <li class="list-group-item" style="cursor: pointer;"
+ *ngFor="let book of books"
+ [ngClass]="{'active': book.id === book_modal.id}"
+ (click)="book_modal = book">
+ {{ book.title | titlecase }}
+ </li>
+ </ul>
+ </div>
+ <!-- ============================================================================================== -->
+ <!-- End column left: List of books -->
+ <!-- ============================================================================================== -->
+
+ <!-- ============================================================================================== -->
+ <!-- Column right: Selected book details -->
+ <!-- ============================================================================================== -->
+ <div class="col-8">
+ <div class="card-body" style="background-color: #FFFFFF;">
+ <div class="row">
+ <div class="col-lg-12">
+ <div class="card" *ngIf="book_modal.title !== ''; else other">
+ <form class="form-horizontal" role="form">
+ <!-- ROW PRINCIPAL -->
+ <div class="form-body">
+ <div class="row">
+ <!-- CARROUSEL BOOK IMAGES -->
+ <div class="col-md-6">
+ <div id="carouselExampleFade" class="carousel slide carousel-fade" data-ride="carousel">
+ <div class="carousel-inner">
+ <div class="carousel-item" *ngFor="let img of book_modal.images; let i=index;" [ngClass]="{'active': i===0}" >
+ <img class="d-block img-carousel" [src]="img">
+ </div>
+ </div>
+ <a class="carousel-control-prev" href="#carouselExampleFade" role="button" data-slide="prev">
+ <span class="carousel-control-prev-icon" aria-hidden="true"></span>
+ </a>
+ <a class="carousel-control-next" href="#carouselExampleFade" role="button" data-slide="next">
+ <span class="carousel-control-next-icon" aria-hidden="true"></span>
+ </a>
+ </div>
+ </div>
+ <!-- CARROUSEL BOOK IMAGES -->
+
+ <div class="col-md-6">
+ <!-- TÍTULO LIBRO -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Título:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.title | titlecase }} </p>
+ </div>
+ </div>
+ <!-- AUTOR/A LIBRO -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Autor/a:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.author | titlecase }} </p>
+ </div>
+ </div>
+ <!-- TIPO DE TRANSACCIÓN -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Tipo de transacción:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.transaction }} </p>
+ </div>
+ </div>
+ <!-- PRECIO LIBRO -->
+ <div class="form-group row"
+ *ngIf="book_modal.transaction === 'Venta' || book_modal.transaction === 'Ambos'">
+ <label class="control-label text-left col-md-6">Precio:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> ${{ book_modal.price | thousands }} </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- ROW DETALLES -->
+ <h3 class="box-title">Detalles</h3>
+ <hr class="m-t-0 m-b-40">
+ <div class="row">
+ <div class="col-md-6">
+ <!-- TIPO DE ELEMENTO -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Elemento:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.type }} </p>
+ </div>
+ </div>
+ <!-- GÉNERO -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Género:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.genres }} </p>
+ </div>
+ </div>
+ <!-- EDITORIAL -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Editorial:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.editorial | titlecase }} </p>
+ </div>
+ </div>
+ <!-- IDIOMA -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Idioma:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.language }} </p>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-md-6">
+ <!-- ORIGINAL -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Original:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.original }} </p>
+ </div>
+ </div>
+ <!-- NÚMERO DE PÁGINAS -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Número de páginas:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.num_page }} </p>
+ </div>
+ </div>
+ <!-- COMENTARIOS -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Comentario:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book_modal.comment }} </p>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="form-actions">
+ <div class="row justify-content-md-center">
+ <!-- BOTÓN EDITAR -->
+ <div class="col-md-4 text-center">
+ <button class="btn btn-outline-info model_img img-responsive"
+ data-toggle="modal"
+ data-target=".bs-example-modal-lg"
+ type="button">
+ <i class="fa fa-pencil"></i> Editar</button>
+ </div>
+ <!-- BOTÓN ELIMINAR -->
+ <div class="col-md-4 text-center">
+ <button class="btn btn-danger img-responsive" type="button"
+ (click)="deleteBook()">
+ <i class="fa fa-trash-o"></i> Eliminar</button>
+ </div>
+ <div class="col-md-6"> </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ <ng-template #other>
+ <div class="alert alert-primary" role="alert">
+ Debe seleccionar un libro
+ </div>
+ </ng-template>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================================================== -->
+ <!-- End column right: Selected book details -->
+ <!-- ============================================================================================== -->
+ </div>
+</div>
+
+<!-- ================================================================================================== -->
+<!-- Modal edit/delete book -->
+<!-- ================================================================================================== -->
+<div id="openModal" class="modal fade bs-example-modal-lg">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <h4 class="modal-title" id="myLargeModalLabel"> {{ book_modal.title | titlecase }} </h4>
+ <!-- Botón para cerrar el modal -->
+ <button _ngcontent-c0="" aria-label="Close" class="close" data-dismiss="modal" type="button">
+ <span _ngcontent-c0="" aria-hidden="true">×</span>
+ </button>
+ </div>
+
+ <div class="modal-body">
+ <form class="form-material m-t-40" >
+ <div class="row">
+ <!-- Inicio col 1 -->
+ <div class="col-6">
+ <div class="form-group">
+ <label>Título</label>
+ <input type="text" [(ngModel)]="book_modal.title" name="title"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: Harry Potter">
+ </div>
+
+ <div class="form-group">
+ <label>Autor/a</label>
+ <input type="text" [(ngModel)]="book_modal.author" name="author"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: J. K. Rowling">
+ </div>
+
+ <div class="form-group">
+ <label>Editorial</label>
+ <input type="text" [(ngModel)]="book_modal.editorial" name="editorial"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: Salamandra">
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Tipo de transacción</label>
+ <select class="form-control" [(ngModel)]="book_modal.transaction" name="transaction">
+ <option value="Intercambio">Intercambio</option>
+ <option value="Venta">Venta</option>
+ <option value="Ambos">Ambos</option>
+ </select>
+ </div>
+
+ <div class="form-group"
+ *ngIf="book_modal.transaction === 'Venta' || book_modal.transaction === 'Ambos'">
+ <label>Precio</label>
+ <input [(ngModel)]="book_modal.price" name="price" onlynumber="true" minlength="3" maxlength="6"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: 5000" required>
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Tipo de elemento</label>
+ <select class="form-control" [(ngModel)]="book_modal.type" name="type">
+ <option value="Libro">Libro</option>
+ <option value="Cómic">Cómic</option>
+ <option value="Lectura especializada">Lectura especializada</option>
+ <option value="Literatura infantil">Literatura infantil</option>
+ <option value="Otro">Otro</option>
+ </select>
+ </div>
+ </div>
+
+ <!-- Inicio col 2 -->
+ <div class="col-6">
+ <div class="form-group border-input-custom">
+ <label>Género al que pertenece</label>
+ <select class="form-control" [(ngModel)]="book_modal.genres" name="genres" multiple>
+ <option value="1">1</option>
+ <option value="2">2</option>
+ <option value="Lectura especializada">Lectura especializada</option>
+ <option value="Literatura infantil">Literatura infantil</option>
+ <option value="Otro">Otro</option>
+ </select>
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Idioma</label>
+ <select class="form-control" [(ngModel)]="book_modal.language" name="language">
+ <option value="Español">Español</option>
+ <option value="Inglés">Inglés</option>
+ <option value="Otro">Otro</option>
+ </select>
+ </div>
+
+ <div class="form-group border-input-custom">
+ <label>Texto original</label>
+ <select class="form-control" [(ngModel)]="book_modal.original" name="original">
+ <option value="Sí">Sí</option>
+ <option value="No">No</option>
+ </select>
+ </div>
+
+ <div class="form-group">
+ <label>Cantidad de páginas</label>
+ <input [(ngModel)]="book_modal.num_page" name="num_pages" onlynumber="true" minlength="2" maxlength="5"
+ class="form-control form-control-line border-input-custom" placeholder="Ej.: 324" required>
+ </div>
+
+ <div class="form-group">
+ <label>Comentario</label>
+ <textarea class="form-control border-input-custom" [(ngModel)]="book_modal.comment" name="comment" rows="2"
+ placeholder="Ej.: El libro se encuentra en buen estado, leído solo una vez.">
+ </textarea>
+ </div>
+ </div>
+
+ <!-- TODO: Agregar el editar las categorías -->
+
+ </div>
+ </form>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-outline-info" (click)="updateBook()">Editar</button>
+ <button type="button" class="btn btn-danger waves-effect text-left" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- ================================================================================================== -->
+<!-- End modal edit/delete book -->
+<!-- ================================================================================================== -->
+ +
+ src/app/components/loading/loading.component.ts
+
+
+ OnInit
+
selector | +app-loading |
+
styleUrls | +./loading.component.css |
+
templateUrl | +./loading.component.html |
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ + | +
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-loading',
+ templateUrl: './loading.component.html',
+ styleUrls: ['./loading.component.css']
+})
+export class LoadingComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+}
+
+ <div class="spinner">
+ <div class="bounce1"></div>
+ <div class="bounce2"></div>
+ <div class="bounce3"></div>
+</div>
+
+
+ ./loading.component.css
+
.spinner {
+ width: 70px;
+ text-align: center;
+ transform:scale(50%);
+}
+
+.spinner > div {
+ width: 18px;
+ height: 18px;
+ background-color: #333;
+
+ border-radius: 100%;
+ display: inline-block;
+ -webkit-animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ /* Prevent first frame from flickering when animation starts */
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.spinner .bounce1 {
+ -webkit-animation-delay: -0.32s;
+ animation-delay: -0.32s;
+}
+
+.spinner .bounce2 {
+ -webkit-animation-delay: -0.16s;
+ animation-delay: -0.16s;
+}
+
+@-webkit-keyframes bouncedelay {
+ 0%, 80%, 100% { -webkit-transform: scale(0.0) }
+ 40% { -webkit-transform: scale(1.0) }
+}
+
+@keyframes bouncedelay {
+ 0%, 80%, 100% {
+ transform: scale(0.0);
+ -webkit-transform: scale(0.0);
+ } 40% {
+ transform: scale(1.0);
+ -webkit-transform: scale(1.0);
+ }
+}
+ +
+ src/app/register/login.component.ts
+
+
+ OnInit
+
selector | +app-login |
+
styleUrls | +./register.component.css |
+
templateUrl | +./login.component.html |
+
+ Properties+ |
+
+ + | +
+ Methods+ |
+
+
|
+
+constructor(afAuth: AngularFireAuth, router: Router, _db: DatabaseService)
+ |
+ ||||||||||||
+ Defined in src/app/register/login.component.ts:28
+ |
+ ||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + forgotPassword + + + + | +
+forgotPassword()
+ |
+
+ Defined in src/app/register/login.component.ts:115
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + loginGoogle + + + + | +
+loginGoogle()
+ |
+
+ Defined in src/app/register/login.component.ts:56
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + loginUser + + + + | +
+loginUser()
+ |
+
+ Defined in src/app/register/login.component.ts:64
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/register/login.component.ts:47
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : FormGroup
+
+ |
+
+ Defined in src/app/register/login.component.ts:26
+ |
+
+ + + + Public + submit + + + + | +
+ submit:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : false
+ |
+
+ Defined in src/app/register/login.component.ts:28
+ |
+
+ + + + Public + user + + + + | +
+ user:
+ |
+
+ Type : any
+
+ |
+
+ Default value : {}
+ |
+
+ Defined in src/app/register/login.component.ts:27
+ |
+
import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FormGroup, FormControl, Validators, FormControlName } from '@angular/forms';
+
+// SERVICES
+import { DatabaseService } from '../services/database.service';
+
+// ANGULARFIRE2
+import { AngularFireAuth } from 'angularfire2/auth';
+import { auth } from 'firebase';
+
+// PLUGINS
+import swal from 'sweetalert';
+import * as firebase from 'firebase';
+
+// Inicializa los plugins
+declare function init_plugins();
+
+@Component({
+ selector: 'app-login',
+ templateUrl: './login.component.html',
+ styleUrls: ['./register.component.css']
+})
+export class LoginComponent implements OnInit {
+
+ form:FormGroup;
+ public user:any = {};
+ public submit:boolean = false;
+
+ constructor( private afAuth: AngularFireAuth,
+ private router:Router,
+ private _db:DatabaseService ) {
+
+ if( JSON.parse(localStorage.getItem('session')).session ) router.navigate(['/']);
+
+ this.afAuth.authState.subscribe( user => {
+ console.log( 'Estado del usuario', user );
+ if( !user ){
+ return;
+ }
+ this.user.name = user.displayName;
+ this.user.uid = user.uid;
+ this.user.email = user.email;
+ });
+ }
+
+ ngOnInit() {
+ init_plugins();
+ this.form = new FormGroup({
+ email: new FormControl(localStorage.getItem('email') || undefined, [Validators.required, Validators.email]),
+ password: new FormControl(undefined, [Validators.required,Validators.minLength(6)]),
+ rememberMe: new FormControl(JSON.parse(localStorage.getItem('session')).rememberMe)
+ });
+ }
+
+ loginGoogle() {
+ this.afAuth.auth.signInWithPopup( new auth.GoogleAuthProvider() )
+ .then( data => {
+ console.log(data);
+ })
+ .catch( e => console.log('error', e));
+ }
+
+ loginUser(){
+ this.submit = true;
+
+ if( this.form.valid ){
+ this.afAuth.auth.signInWithEmailAndPassword(this.form.value['email'], this.form.value['password'])
+ .then( (resp) => {
+ const USER = resp.user;
+
+ this._db.getDataQuery('users', 'uid', '==', USER.uid)
+ .valueChanges()
+ .subscribe( resp => {
+ if (!resp[0].status){
+ this.afAuth.auth.signOut();
+ swal('Su cuenta no se encuentra activa', 'Si desea activar su cuenta comunicarse con la administradora al siguiente email: JavieraOrmeno.L@gmail.com', 'warning');
+ }else{
+ let userStorage = {
+ uid: USER.uid,
+ email: USER.email,
+ name: resp[0].name,
+ last_name1: resp[0].last_name1,
+ last_name2: resp[0].last_name2,
+ role: resp[0].role,
+ img: resp[0].img
+ };
+
+ if( this.form.value['rememberMe'] ){
+ localStorage.setItem('email', USER.email);
+ }else {
+ localStorage.removeItem('email');
+ }
+
+ localStorage.setItem('user', JSON.stringify(userStorage));
+ localStorage.setItem('session', JSON.stringify({
+ rememberMe: this.form.value['rememberMe'],
+ session: true
+ }));
+
+ // Redirige a dashboard o home según el rol del usuario
+ if ( userStorage.role == 'admin' ){
+ this.router.navigate(['/admin']);
+ }else if ( userStorage.role == 'normal' ){
+ this.router.navigate(['/home']);
+ }
+ }
+ });
+ })
+ .catch( () => swal('Usuario o contraseña incorrectos', 'Por favor vuelva a intentarlo', 'warning') );
+ }
+ }
+
+ // Envía un correo desde Firebase para restaurar la contraseña
+ forgotPassword(){
+ let auth = firebase.auth();
+
+ auth.sendPasswordResetEmail(this.form.value['email'])
+ .then(() => {
+ swal('Correo enviado', 'Se ha enviado un correo para restaurar la contraseña', 'success');
+ })
+ .catch( () => {
+ swal('Error al enviar correo', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ }
+}
+
+ <section id="wrapper">
+ <div class="login-register" style="background-image:url(../../assets/images/background/book-2.jpg);">
+ <div class="login-box card">
+ <div class="card-body">
+
+ <!-- ============================================================================== -->
+ <!-- Login -->
+ <!-- ============================================================================== -->
+ <form class="form-horizontal form-material"
+ [formGroup]="form"
+ (ngSubmit)="loginUser()"
+ novalidate="novalidate"
+ action="index.html">
+
+ <h3 class="box-title m-b-20"> Ingresar </h3>
+ <div class="form-group">
+ <div class="col-xs-12">
+ <input formControlName="email"
+ class="form-control"
+ type="text"
+ placeholder="Correo electrónico">
+ </div>
+ <p class="text-danger" *ngIf="submit && form.controls['email'].errors?.required"> El correo es requerido </p>
+ <p class="text-danger" *ngIf="submit && form.controls['email'].errors?.email"> El correo no es valido </p>
+ </div>
+
+ <div class="form-group">
+ <div class="col-xs-12">
+ <input formControlName="password"
+ class="form-control"
+ type="password"
+ placeholder="Password">
+ <p class="text-danger" *ngIf="submit && form.controls['password'].errors?.required">
+ La contraseña es requerida
+ </p>
+ <p class="text-danger"
+ *ngIf="submit &&
+ form.controls['password'].errors?.minlength.actualLength !== undefined &&
+ form.controls['password'].errors?.minlength.actualLength < form.controls['password'].errors?.minlength.requiredLength">
+ La es demasiado corta
+ </p>
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <div class="col-md-12">
+ <div class="checkbox checkbox-info pull-left p-t-0">
+ <input formControlName="rememberMe"
+ id="checkbox-signup"
+ type="checkbox"
+ class="filled-in chk-col-light-blue">
+ <label for="checkbox-signup"> Recuérdame </label>
+ </div>
+ <a href="javascript:void(0)" id="to-recover" class="text-dark pull-right" (click)="forgotPassword()">
+ <i class="fa fa-lock m-r-5"></i> Olvidó su contraseña?
+ </a>
+ </div>
+ </div>
+
+ <div class="form-group text-center">
+ <div class="col-xs-12 p-b-20">
+ <button class="btn btn-block btn-lg btn-info btn-rounded" type="submit">Ingresar</button>
+ </div>
+ </div>
+
+ <!-- Login with Google button -->
+ <div class="row">
+ <div class="col-xs-12 col-sm-12 col-md-12 m-t-10 text-center">
+ <div class="social">
+ <button (click)="loginGoogle()"
+ type="button"
+ id="btnGoogle"
+ class="btn btn-googleplus"
+ data-toggle="tooltip"
+ title="Iniciar sesión con Google">
+ <i aria-hidden="true" class="fa fa-google-plus"></i>
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <!-- Register me -->
+ <div class="form-group m-b-0">
+ <div class="col-sm-12 text-center">No tienes una cuenta?
+ <a [routerLink]="['/register']" class="text-info m-l-5">
+ <b>Registrarme</b>
+ </a>
+ </div>
+ </div>
+ </form>
+ <!-- ============================================================================== -->
+ <!-- End Login -->
+ <!-- ============================================================================== -->
+
+
+ <!-- ============================================================================== -->
+ <!-- Recovery password -->
+ <!-- ============================================================================== -->
+ <form class="form-horizontal" id="recoverform" action="index.html">
+ <div class="form-group">
+ <div class="col-xs-12">
+ <h3>Recuperar contraseña</h3>
+ <p class="text-muted">Ingresa tu correo electrónico y te enviaremos las instrucciones</p>
+ </div>
+ </div>
+
+ <div class="form-group ">
+ <div class="col-xs-12">
+ <input class="form-control" type="text" required="" placeholder="Email"> </div>
+ </div>
+ <div class="form-group text-center m-t-20">
+ <div class="col-xs-12">
+ <button class="btn btn-primary btn-lg btn-block text-uppercase waves-effect waves-light" type="submit">Reset</button>
+ </div>
+ </div>
+ </form>
+ <!-- ============================================================================== -->
+ <!-- End recovery password -->
+ <!-- ============================================================================== -->
+
+ </div>
+ </div>
+ </div>
+</section>
+
+ ./register.component.css
+
.login-register {
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: center center;
+ height: 160%;
+ width: 100%;
+ padding: 10% 0;
+ position: absolute; }
+
+.login-box {
+ width: 100%;
+ max-width: 580px;
+ margin: 0 auto; }
+ .login-box .footer {
+ width: 100%;
+ left: 0px;
+ right: 0px; }
+ .login-box .social {
+ display: block;
+ margin-bottom: 30px; }
+
+#recoverform {
+ display: none; }
+
+.login-sidebar {
+ padding: 0px;
+ margin-top: 0px; }
+ .login-sidebar .login-box {
+ right: 0px;
+ position: absolute;
+ height: 100%; }
+
+.contenedor {
+ max-width: 220px !important;
+ min-width: 220px !important;
+}
+
+.ms-container {
+ width: 100%;
+}
+
+ +
+ src/app/pages/message-admin/message-admin.component.ts
+
selector | +app-message-admin |
+
styleUrls | +./message-admin.component.css |
+
templateUrl | +./message-admin.component.html |
+
+ Properties+ |
+
+ + | +
+constructor(_dbService: DatabaseService)
+ |
+ ||||||
+ + | +||||||
+
+ Parameters :
+
+
|
+
+ + + + loader + + + + | +
+ loader:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : true
+ |
+
+ + | +
+ + + + messages + + + + | +
+ messages:
+ |
+
+ Type : any[]
+
+ |
+
+ + | +
+ + + + selected + + + + | +
+ selected:
+ |
+
+ Type : any
+
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+
+import { DatabaseService } from '../../services/database.service';
+
+@Component({
+ selector: 'app-message-admin',
+ templateUrl: './message-admin.component.html',
+ styleUrls: ['./message-admin.component.css']
+})
+export class MessageAdminComponent {
+
+ messages:any[];
+ selected:any;
+ loader:boolean = true;
+
+ constructor( _dbService: DatabaseService ) {
+ _dbService.getData('global-messages')
+ .valueChanges()
+ .subscribe( resp => {
+ this.messages = resp;
+ this.loader = false;
+ });
+ }
+}
+
+
+<div class="container">
+ <h2 class="mt-3"> Novedades </h2>
+ <div class="row mt-5">
+ <div class="col-3">
+ <ul *ngIf="!loader" class="list-group shadow-box">
+ <li *ngFor="let message of messages"
+ class="list-group-item"
+ style="cursor: pointer"
+ [ngClass]="{'active': selected !== undefined && selected.day === message.day }">
+ <a (click)="selected = message"> {{ message.title }} </a>
+ </li>
+ </ul>
+
+ <div *ngIf="loader" class="loader">
+ <p>Buscando mensajes...</p>
+ <app-loading></app-loading>
+ </div>
+ </div>
+
+ <div class="col-8">
+ <div *ngIf="selected !== undefined;" class="message shadow-box">
+ <h3> {{ selected.title }} </h3>
+ <p> {{ selected.body }} </p>
+ <span> {{ selected.hour }} </span>
+ </div>
+
+ <div *ngIf="selected === undefined" class="no-message shadow-box">
+ <h3> Debe seleccionar un mensaje </h3>
+ </div>
+ </div>
+
+ </div>
+</div>
+
+
+ ./message-admin.component.css
+
.message,
+.no-message {
+ background: #fff;
+ padding: 1rem;
+ border-radius: 8px;
+ border: 2px solid #2321;
+
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.message span {
+ align-self: flex-end;
+ font-size: .8rem;
+}
+
+.no-message {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: center;
+ background: #d3a9a9;
+ padding: 2rem;
+}
+
+.loader {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+ +
+ src/app/shared/messages/messages.component.ts
+
selector | +app-messages |
+
styleUrls | +./messages.component.css |
+
templateUrl | +./messages.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, router: Router)
+ |
+ |||||||||
+ + | +|||||||||
+
+ Parameters :
+
+
|
+
+ + + + showMessage + + + + | +||||||
+showMessage($key: string)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + messages + + + + | +
+ messages:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + new_messages + + + + | +
+ new_messages:
+ |
+
+ Type : number
+
+ |
+
+ Default value : 0
+ |
+
+ + | +
+ + + + uid + + + + | +
+ uid:
+ |
+
+ Type : string
+
+ |
+
+ + | +
import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+
+// SERVICIOS
+import { DatabaseService } from '../../services/database.service';
+
+import { map } from 'rxjs/operators';
+
+@Component({
+ selector: 'app-messages',
+ templateUrl: './messages.component.html',
+ styleUrls: ['./messages.component.css']
+})
+export class MessagesComponent {
+
+ uid:string;
+ messages:any = [];
+ new_messages:number = 0;
+
+ constructor( private _dbService:DatabaseService, private router: Router ) {
+ this.uid = JSON.parse(localStorage.getItem('user')).uid;
+
+ this._dbService.getData('messages-transaction')
+ .snapshotChanges()
+ .pipe(
+ map( actions => actions.map(a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+ return { key, ...data };
+ })),
+ map( (res:any) => {
+ let arr = [];
+ for(let r of res){
+ if( r.user_owner === this.uid || r.uid_interested.uid === this.uid )
+ arr.push(r);
+ }
+ return arr;
+ })
+ )
+ .subscribe( data => {
+ this.messages = [];
+ this.messages = data;
+ });
+
+ // Obtener la cantidad de mensajes no leidos
+ this._dbService.getDataQuery('messages-transaction', 'status', '==', false)
+ .valueChanges()
+ .subscribe( data => this.new_messages = data.length );
+ }
+
+ showMessage( $key:string ){
+ this.router.navigate(['/messages', $key]);
+ }
+}
+
+ <div class="dropdown-menu mailbox dropdown-menu-right animated bounceInDown chaoOverflow" aria-labelledby="2">
+ <ul>
+ <li>
+ <div class="drop-title">Tienes {{ new_messages }} mensaje/s</div>
+ </li>
+ <li style="height: 200px;">
+ <div class="message-center">
+ <a *ngFor="let m of messages; let i = index;" class="pointer" (click)="showMessage(m.key)">
+ <div class="user-img">
+ <img *ngIf="m.uid_interested.uid !== uid" class="img-circle img-circle-40" [src]="m.uid_interested.img">
+ <img *ngIf="m.user_owner !== uid" class="img-circle img-circle-40" [src]="m.book.user.img">
+ <span [ngClass]="{'online': m.status, 'busy': !m.status}" class="profile-status pull-right"></span>
+ <!-- TODO: Estado del mensaje -->
+ <!-- online es verde, busy es rojo, away es naranjo, offline es naranjo -->
+ </div>
+ <div class="mail-contnet">
+ <h5 *ngIf="m.uid_interested.uid !== uid"> {{ m.uid_interested.name | titlecase }} {{ m.uid_interested.last_name1 | titlecase }} {{ m.uid_interested.last_name2 | titlecase }} </h5>
+ <h5 *ngIf="m.user_owner !== uid"> {{ m.book.user.name | titlecase }} {{ m.book.user.last_name1 | titlecase }} {{ m.book.user.last_name2 | titlecase }} </h5>
+ <span class="mail-desc"> {{ m.text[m.text.length-1][m.user_owner] }} {{ m.text[m.text.length-1][m.uid_interested.uid] }} </span>
+ <span class="time"> {{ m.date }} </span>
+ </div>
+ </a>
+ </div>
+ </li>
+ <li>
+ <a class="nav-link text-center" [routerLink]="['/messages']">
+ <strong>Ver todos los mensajes</strong>
+ <i class="fa fa-angle-right"></i>
+ </a>
+ </li>
+ </ul>
+ <!-- TODO: Dejarlo como footer -->
+</div>
+
+ ./messages.component.css
+
+ +
+ src/app/shared/notifications/notifications.component.ts
+
+
+ OnInit
+
selector | +app-notifications |
+
styleUrls | +./notifications.component.css |
+
templateUrl | +./notifications.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService)
+ |
+ ||||||
+ + | +||||||
+
+ Parameters :
+
+
|
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + messages + + + + | +
+ messages:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + new_messages + + + + | +
+ new_messages:
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { DatabaseService } from 'src/app/services/database.service';
+
+@Component({
+ selector: 'app-notifications',
+ templateUrl: './notifications.component.html',
+ styleUrls: ['./notifications.component.css']
+})
+export class NotificationsComponent implements OnInit {
+
+ messages: any = [];
+ new_messages
+
+ constructor( private _dbService:DatabaseService ) {
+
+ this._dbService.getData( "global-messages")
+ .valueChanges()
+ .subscribe( data => {
+ this.messages = [];
+ this.messages = data;
+ });
+
+ // Obtener la cantidad de mensajes no leidos
+ this._dbService.getDataQuery('global-messages', 'status', '==', false)
+ .valueChanges()
+ .subscribe( data => this.new_messages = data.length );
+ }
+
+ ngOnInit() {
+ }
+
+}
+
+ <div class="dropdown-menu dropdown-menu-right mailbox animated bounceInDown chaoOverflow">
+ <ul>
+ <li>
+ <div class="drop-title">Mensajes del Administrador</div>
+ </li>
+ <li>
+ <div class="drop-title" style="font-size: 13px;">Tienes {{ new_messages }} mensaje/s</div>
+ </li>
+ <li>
+ <div class="message-center ps ps--theme_default">
+ <!-- Message -->
+ <a href="#" *ngFor="let m of messages">
+ <div class="btn btn-info btn-circle"><i class="ti-user"></i></div>
+ <div class="mail-contnet">
+ <h5>{{ m.title }}</h5>
+ <span class="mail-desc">{{ m.body }}</span>
+ <span class="time">{{ m.day }} - {{ m.hour }}</span>
+ </div>
+ </a>
+ <div class="ps__scrollbar-x-rail" style="left: 0px; bottom: 0px;">
+ <div class="ps__scrollbar-x" tabindex="0" style="left: 0px; width: 0px;"></div>
+ </div>
+ <div class="ps__scrollbar-y-rail" style="top: 0px; right: 0px;">
+ <div class="ps__scrollbar-y" tabindex="0" style="top: 0px; height: 0px;"></div>
+ </div>
+ </div>
+ </li>
+ <li>
+ <a class="nav-link text-center" href="javascript:void(0);" style="font-size: 12px;">
+ <strong>Ver todos los mensajes del Administrador</strong>
+ <i class="fa fa-angle-right"></i>
+ </a>
+ </li>
+ </ul>
+</div>
+
+ ./notifications.component.css
+
+ +
+ src/app/components/one-book/one-book.component.ts
+
+
+ OnInit
+
selector | +app-one-book |
+
templateUrl | +./one-book.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+ Inputs+ |
+
+
|
+
+constructor(formBuilder: FormBuilder, _dbService: DatabaseService)
+ |
+ |||||||||
+ + | +|||||||||
+
+ Parameters :
+
+
|
+
+
+ book
+ |
+
+
+ Type : |
+
+ + | +
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + editForm + + + + | +
+ editForm:
+ |
+
+ Type : FormGroup
+
+ |
+
+ + | +
import { Component, OnInit, Input } from '@angular/core';
+import { FormBuilder, FormGroup, FormControl } from "@angular/forms";
+
+import { Books } from "../../interface/books.interface";
+import { DatabaseService } from "../../services/database.service";
+
+
+@Component({
+ selector: 'app-one-book',
+ templateUrl: './one-book.component.html'
+})
+export class OneBookComponent implements OnInit {
+
+ @Input() book:Books;
+
+ editForm:FormGroup;
+
+ constructor( private formBuilder: FormBuilder,
+ private _dbService:DatabaseService, ) {
+ let user = JSON.parse( localStorage.getItem( "user" ) );
+ }
+
+ ngOnInit() {
+ }
+
+}
+
+
+<div class="card-body" style="background-color: #FFFFFF;">
+ <!-- Row -->
+ <div class="row">
+ <div class="col-lg-12">
+ <div class="card">
+ <form class="form-horizontal" role="form">
+ <div class="form-body">
+ <div class="row">
+
+ <!-- CARROUSEL IMAGES -->
+ <div class="col-md-6">
+ <div id="carouselExampleFade" class="carousel slide carousel-fade" data-ride="carousel">
+ <div class="carousel-inner">
+ <div class="carousel-item" *ngFor="let img of book.images; let i=index;" [ngClass]="{'active': i===0}" >
+ <img class="d-block img-carousel" [src]="img">
+ </div>
+ </div>
+ <a class="carousel-control-prev" href="#carouselExampleFade" role="button" data-slide="prev">
+ <span class="carousel-control-prev-icon" aria-hidden="true"></span>
+ </a>
+ <a class="carousel-control-next" href="#carouselExampleFade" role="button" data-slide="next">
+ <span class="carousel-control-next-icon" aria-hidden="true"></span>
+ </a>
+ </div>
+ </div>
+ <!-- CARROUSEL IMAGES -->
+
+ <div class="col-md-6">
+ <!-- TITLE -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Título:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.title }} </p>
+ </div>
+ </div>
+
+ <!-- AUTHOR -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Autor/a:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.author }} </p>
+ </div>
+ </div>
+
+ <!-- TRANSACTION TYPE -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Tipo de transacción:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.transaction }} </p>
+ </div>
+ </div>
+
+ <!-- PRICE -->
+ <div class="form-group row" *ngIf="book.transaction == 'Venta' || book.transaction == 'Both'">
+ <label class="control-label text-left col-md-6">Precio:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.price | thousands }} </p>
+ </div>
+ </div>
+
+ <!-- PUBLICATION DATE -->
+ <div class="form-group row" *ngIf="book.transaction == 'Venta' || book.transaction == 'Both'">
+ <label class="control-label text-left col-md-6">Fecha de publicación:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.date }} </p>
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Dueño:</label>
+ <div class="col-md-6">
+
+ <p class="form-control-static">
+ {{ book.user.name | titlecase }}
+ {{ book.user.last_name1 | titlecase }}
+ {{ book.user.last_name2 | titlecase }}
+ </p>
+
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- ROW DETALLES -->
+ <h3 class="box-title">Detalles</h3>
+ <hr class="m-t-0 m-b-40">
+ <div class="row">
+
+ <div class="col-md-6">
+ <!-- TIPO DE ELEMENTO -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Elemento:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.type }} </p>
+ </div>
+ </div>
+
+ <!-- GÉNERO -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Género:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.categories }} </p>
+ </div>
+ </div>
+
+ <!-- EDITORIAL -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Editorial:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.editorial }} </p>
+ </div>
+ </div>
+
+ <!-- IDIOMA -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Idioma:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.language }} </p>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-md-6">
+ <!-- ORIGINAL -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Original:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.original }} </p>
+ </div>
+ </div>
+
+ <!-- NÚMERO DE PÁGINAS -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Número de páginas:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.num_page }} </p>
+ </div>
+ </div>
+
+ <!-- COMENTARIOS -->
+ <div class="form-group row">
+ <label class="control-label text-left col-md-6">Comentario:</label>
+ <div class="col-md-6">
+ <p class="form-control-static"> {{ book.comment }} </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ <!-- Row -->
+ </div>
+
+ +
+ src/app/pageforbidden/pageforbidden.component.ts
+
+
+ OnInit
+
selector | +app-pageforbidden |
+
styleUrls | +./pageforbidden.component.css |
+
templateUrl | +./pageforbidden.component.html |
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ + | +
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+// Inicializa los plugins
+declare function init_plugins();
+
+@Component({
+ selector: 'app-pageforbidden',
+ templateUrl: './pageforbidden.component.html',
+ styleUrls: ['./pageforbidden.component.css']
+})
+export class PageforbiddenComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ init_plugins();
+ }
+
+}
+
+ <div id="notfound">
+ <div class="notfound">
+ <div class="notfound-404">
+ <h3>Oops! Usted no tiene acceso a esta página</h3>
+ <!-- <h1><span></span><span>0</span><span>3</span></h1> -->
+ <div class="background"></div>
+ </div>
+ <h2>Lo sentimos, pero usted no tiene acceso a la página solicitada, intente volver al <a [routerLink]="['/home']">Home</a></h2>
+ </div>
+ </div>
+
+ ./pageforbidden.component.css
+
* {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+
+ body {
+ padding: 0;
+ margin: 0;
+ }
+
+ #notfound {
+ position: relative;
+ height: 100vh;
+ }
+
+ #notfound .notfound {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ }
+
+ .notfound {
+ max-width: 520px;
+ width: 100%;
+ line-height: 1.4;
+ text-align: center;
+ }
+
+ .notfound .notfound-404 {
+ position: relative;
+ height: 240px;
+ }
+
+ .notfound .notfound-404 h1 {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ font-size: 252px;
+ font-weight: 900;
+ margin: 0px;
+ color: #262626;
+ text-transform: uppercase;
+ letter-spacing: -40px;
+ margin-left: -20px;
+ }
+
+ .notfound .notfound-404 h1>span {
+ text-shadow: -8px 0px 0px #fff;
+ }
+
+ .notfound .notfound-404 h3 {
+ position: relative;
+ font-size: 16px;
+ font-weight: 700;
+ text-transform: uppercase;
+ color: #262626;
+ margin: 0px;
+ letter-spacing: 3px;
+ padding-left: 6px;
+ }
+
+ .notfound h2 {
+ font-size: 20px;
+ font-weight: 400;
+ color: #000;
+ padding-top: 187px;
+ }
+
+ .background {
+ height: 158%;
+ width: 100%;
+ background-image: url("../../assets/images/emoji.png");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: fixed;
+ }
+
+ @media only screen and (max-width: 767px) {
+ .notfound .notfound-404 {
+ height: 200px;
+ }
+ .notfound .notfound-404 h1 {
+ font-size: 200px;
+ }
+ }
+
+ @media only screen and (max-width: 480px) {
+ .notfound .notfound-404 {
+ height: 162px;
+ }
+ .notfound .notfound-404 h1 {
+ font-size: 162px;
+ height: 150px;
+ line-height: 162px;
+ }
+ .notfound h2 {
+ font-size: 16px;
+ }
+ }
+
+ +
+ src/app/pagenotfound/pagenotfound.component.ts
+
+
+ OnInit
+
selector | +app-pagenotfound |
+
styleUrls | +./pagenotfound.component.css |
+
templateUrl | +./pagenotfound.component.html |
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ + | +
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+// Inicializa los plugins
+declare function init_plugins();
+
+@Component({
+ selector: 'app-pagenotfound',
+ templateUrl: './pagenotfound.component.html',
+ styleUrls: ['./pagenotfound.component.css']
+})
+export class PagenotfoundComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ init_plugins();
+ }
+
+}
+
+ <div id="notfound">
+ <div class="notfound">
+ <div class="notfound-404">
+ <h3>Oops! Página no encontrada</h3>
+ <!-- <h1><span>4</span><span>0</span><span>4</span></h1> -->
+ <div class="background"></div>
+ </div>
+ <h2>Lo sentimos, pero no hemos podido encontrar la página solicitada</h2>
+ </div>
+</div>
+
+ ./pagenotfound.component.css
+
* {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+body {
+ padding: 0;
+ margin: 0;
+}
+
+#notfound {
+ position: relative;
+ height: 100vh;
+}
+
+#notfound .notfound {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.notfound {
+ max-width: 520px;
+ width: 100%;
+ line-height: 1.4;
+ text-align: center;
+}
+
+.notfound .notfound-404 {
+ position: relative;
+ height: 240px;
+}
+
+.notfound .notfound-404 h1 {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ font-size: 252px;
+ font-weight: 900;
+ margin: 0px;
+ color: #262626;
+ text-transform: uppercase;
+ letter-spacing: -40px;
+ margin-left: -20px;
+}
+
+.notfound .notfound-404 h1>span {
+ text-shadow: -8px 0px 0px #fff;
+}
+
+.notfound .notfound-404 h3 {
+ position: relative;
+ font-size: 16px;
+ font-weight: 700;
+ text-transform: uppercase;
+ color: #262626;
+ margin: 0px;
+ letter-spacing: 3px;
+ padding-left: 6px;
+}
+
+.notfound h2 {
+ font-size: 20px;
+ font-weight: 400;
+ color: #000;
+ padding-top: 187px;
+}
+
+.background {
+ height: 158%;
+ width: 100%;
+ background-image: url("../../assets/images/Pagenotfound.jpeg");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: fixed;
+}
+
+@media only screen and (max-width: 767px) {
+ .notfound .notfound-404 {
+ height: 200px;
+ }
+ .notfound .notfound-404 h1 {
+ font-size: 200px;
+ }
+}
+
+@media only screen and (max-width: 480px) {
+ .notfound .notfound-404 {
+ height: 162px;
+ }
+ .notfound .notfound-404 h1 {
+ font-size: 162px;
+ height: 150px;
+ line-height: 162px;
+ }
+ .notfound h2 {
+ font-size: 16px;
+ }
+}
+
+ +
+ src/app/pages/pages.component.ts
+
+
+ OnInit
+
selector | +app-pages |
+
templateUrl | +./pages.component.html |
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ Defined in src/app/pages/pages.component.ts:10
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/pages/pages.component.ts:15
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+// Inicializa los plugins
+declare function init_plugins();
+
+@Component({
+ selector: 'app-pages',
+ templateUrl: './pages.component.html'
+})
+export class PagesComponent implements OnInit {
+
+ constructor() {
+ }
+
+ ngOnInit() {
+ init_plugins();
+ }
+
+
+}
+
+
+<div id="main-wrapper">
+ <app-header></app-header>
+ <app-sidebar></app-sidebar>
+
+ <!-- ============================================================== -->
+ <!-- Page wrapper -->
+ <!-- ============================================================== -->
+ <div class="page-wrapper">
+ <!-- ============================================================== -->
+ <!-- Container fluid -->
+ <!-- ============================================================== -->
+ <div class="container-fluid">
+
+ <!-- ============================================================== -->
+ <!-- Start Page Content -->
+ <!-- ============================================================== -->
+ <router-outlet></router-outlet>
+ <!-- ============================================================== -->
+ <!-- End Page Content -->
+ <!-- ============================================================== -->
+ </div>
+ <!-- ============================================================== -->
+ <!-- END Container fluid -->
+ <!-- ============================================================== -->
+ </div>
+ <!-- ============================================================== -->
+ <!-- END Page wrapper -->
+ <!-- ============================================================== -->
+</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!-- Barra de opción de vistas -->
+<!-- <div class="container">
+ <div class="row">
+ <div class="col-4"></div>
+ <div class="col-4">
+ <div class="btn-group btn-group-toggle">
+ <label class="btn btn-secondary active">
+ <a href="#" class="">Todos</a>
+ </label>
+ <label class="btn btn-secondary">
+ <a href="#" class="">Intercambio</a>
+ </label>
+ <label class="btn btn-secondary">
+ <a href="#" class="">Ventas</a>
+ </label>
+ <label class="btn btn-secondary">
+ <a href="#" class="">Ambos</a>
+ </label>
+ </div>
+ </div>
+ <div class="col-4"></div>
+ </div>
+</div>
+ -->
+
+
+<!-- <app-card-book></app-card-book> -->
+
+<!-- <app-add-book></app-add-book> -->
+
+
+<!-- [heroe] es el nombre de la propiedad y "heroe" es el nombre de la variable local -->
+<!-- <app-books-card [book]="heroe" [index]="i" *ngFor="let book of books; let i = index"></app-books-card> -->
+
+
+
+ +
+ src/app/pages/profile/profile.component.ts
+
+
+ OnInit
+
selector | +app-profile |
+
templateUrl | +./profile.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, auth: AngularFireAuth, router: Router, acRoute: ActivatedRoute)
+ |
+ |||||||||||||||
+ + | +|||||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + addPreference + + + + | +
+addPreference()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + deleteAccount + + + + | +
+deleteAccount()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + deletePreference + + + + | +||||||
+deletePreference(index: number)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + resetUser + + + + | +
+resetUser()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + updateProfile + + + + | +
+updateProfile()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + uploadFile + + + + | +||||
+uploadFile(event)
+ |
+ ||||
+ + | +||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + count_book + + + + | +
+ count_book:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : FormGroup
+
+ |
+
+ + | +
+ + + + p_selected + + + + | +
+ p_selected:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + preferences + + + + | +
+ preferences:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + preferences_modal + + + + | +
+ preferences_modal:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + profile + + + + | +
+ profile:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + profile_options + + + + | +
+ profile_options:
+ |
+
+ Type : string
+
+ |
+
+ + | +
+ + + + uid + + + + | +
+ uid:
+ |
+
+ Type : string
+
+ |
+
+ + | +
+ + + + urlImgs + + + + | +
+ urlImgs:
+ |
+
+ Type : string
+
+ |
+
+ + | +
+ + + + user_profile + + + + | +
+ user_profile:
+ |
+
+ Type : any
+
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormControl, Validators } from '@angular/forms';
+import { Router, ActivatedRoute } from '@angular/router';
+import { map } from 'rxjs/operators';
+
+// SERVICE
+import { DatabaseService } from "../../services/database.service";
+
+// ANGULARFIRE2
+import * as firebase from 'firebase';
+import { AngularFireAuth } from 'angularfire2/auth';
+
+@Component({
+ selector: 'app-profile',
+ templateUrl: './profile.component.html'
+})
+export class ProfileComponent implements OnInit {
+
+ form:FormGroup;
+ profile_options:string; // Controla las opciones en Mi Perfil
+ profile:any;
+ user_profile: any;
+ uid:string; // uid usuario actual
+ count_book:any; // Contador de libros del usuario actual
+ preferences_modal:any;
+ preferences:any; // Todas las preferencais
+ p_selected:any; // Preferencias seleccionadas
+ urlImgs:string; // Guarda la ruta de la imagen para guardar en DB
+
+
+ constructor( private _dbService:DatabaseService,
+ private auth:AngularFireAuth,
+ private router: Router,
+ private acRoute:ActivatedRoute ) {
+
+ this.acRoute.params.subscribe( params => {
+ const input:string = params['input'];
+
+ if( input === 'preferences' ) this.profile_options = 'preference_profile';
+ else this.profile_options = 'my_profile';
+
+ this.preferences_modal = {
+ hour: '',
+ day: '',
+ subway_station: ''
+ };
+
+ let actual_user = JSON.parse( localStorage.getItem( "user" ) );
+
+ this._dbService.getDataQuery( "users", "uid", "==", actual_user.uid )
+ .snapshotChanges()
+ .pipe(
+ map(actions => actions.map(a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+ return { key, ...data };
+ }))
+ ).subscribe( data => {
+ this.profile = data[0];
+ this.preferences = this.profile.preferences;
+ });
+
+ this._dbService.getDataQuery("books", "uid", "==", actual_user.uid)
+ .valueChanges()
+ .subscribe( data => this.count_book = data.length );
+ });
+ }
+
+ ngOnInit() {
+ this.resetUser();
+
+ this.form = new FormGroup({
+ subway_station: new FormControl(undefined, Validators.required),
+ day: new FormControl(undefined, Validators.required),
+ hour: new FormControl(undefined, Validators.required)
+ });
+
+ this.uid = JSON.parse(localStorage.getItem('user')).uid;
+ }
+
+ // Actualiza los datos de perfil del usuario en la DB
+ updateProfile(){
+ this.profile.img = this.urlImgs;
+
+ this._dbService.updateData( "users", this.profile.key, this.profile )
+ .then( () => {
+ swal('Cambios guardados', 'Sus cambios han sidos guardados con éxito', 'success');
+ })
+ .catch( () => {
+ swal('Error al editar', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ }
+
+ // TODO: Falta revisar si la nueva preferencia ya existe.
+ // Agrega la nueva preferencia a la DB
+ addPreference(){
+ if ( this.form.invalid ) {
+ swal(
+ 'Debe completar el formulario',
+ 'Debe ingresar todos los campos de este formulario',
+ 'warning'
+ );
+ return;
+ }
+
+ let pref:any = this.form.value; // Asigna la nueva preferencia a la variable a actualizar
+
+ if(this.profile.preferences === undefined ){
+ this.profile.preferences = [pref];
+ }else {
+ this.profile.preferences.push(pref);
+ }
+
+ this._dbService.updateData( "users", this.profile.key, this.profile )
+ .then( () => {
+ swal('Preferencia agregada', 'Su preferencia ha sido agregada con éxito', 'success');
+ })
+ .catch( () => {
+ swal('Error al agregar su preferencia', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ }
+
+ // Invalida la cuenta del usuario, no la borra, solo le cambia el estado
+ deleteAccount(){
+ this.profile.status = false;
+ swal({
+ title: "Está seguro que desea eliminar su cuenta?",
+ text: "Si luego desea volver a restaurar su cuenta, debe enviar un correo a JavieraOrmeno.L@gmail.com",
+ icon: "warning",
+ buttons: ['Cancelar', 'Confirmar'],
+ dangerMode: true,
+ })
+ .then((willDelete) => {
+ if (willDelete) {
+ this.profile.status = false;
+
+ this._dbService.updateData( "users", this.profile.key, this.profile )
+ .then( () => {
+ this._dbService.getDataQuery('books', 'uid', '==', this.profile.uid)
+ .snapshotChanges()
+ .pipe(
+ map( actions => actions.map( a => {
+ const data = a.payload.doc.data();
+ const key = a.payload.doc.id;
+ return { key, ...data };
+ }))
+ )
+ .subscribe( books => {
+ for(let book of books) {
+ book.status = 'removed';
+ this._dbService.updateData('books', book.key, book);
+ }
+
+ swal("Su cuenta ha sido eliminada con éxito", {
+ icon: "success",
+ })
+ .then( () => this.auth.auth.signOut() )
+ .then( () => this.router.navigate(['/login']));
+ });
+ })
+ .catch( () => {
+ swal('Error al eliminar su cuenta', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ } else {
+ swal("Su cuenta sigue activa", 'error');
+ }
+ });
+ }
+
+ // Elimina la preferencia seleccionada del usuario
+ deletePreference(index:number){
+ this.profile.preferences.splice(index, 1);
+ this._dbService.updateData( "users", this.profile.key, this.profile )
+ .then( () => {
+ swal('Preferencia eliminada', 'La preferencia seleccionada ha sido eliminada con éxito', 'success');
+ })
+ .catch( () => {
+ swal('Error al eliminar', 'Por favor, vuelva a intentarlo', 'error');
+ });
+ }
+
+ // Carga las imagenes al storage de Firebase
+ uploadFile(event) {
+ let file = event.target.files;
+ let url:string; // guarda las imagenes correctas para luego subirlas
+ let aux = false; // para que no se cargen imagenes si existe aunque sea 1 mala
+
+ const separatedFile = file[0].name.split('.');
+ const extension = separatedFile[separatedFile.length - 1];
+
+ const typeValid = ['jpg', 'jpeg', 'png'];
+
+ // Valida las extensiones de las imagenes
+ if( typeValid.indexOf( extension ) <= -1){
+ swal(
+ 'Error al ingresar imagen',
+ 'Extensiones válidas (png, jpg, jpeg), vuelva a intentarlo',
+ 'error'
+ );
+ aux = true;
+ return;
+ }
+
+ if( !aux ){
+ const storageRef = firebase.storage().ref();
+ let filePath = this.uid;
+
+ const uploadTask:firebase.storage.UploadTask =
+ storageRef.child(`profile_img/${ filePath }`)
+ .put(file[0])
+
+ uploadTask.on('state_changed',
+ () => {}, // Manejo de carga
+ (error) => { // Manejo de errores
+ console.log('Error al cargar imagen' ,error);
+ swal('Error al cargar imagenes', 'Por favor, vueva a intentarlo', 'error');
+ },
+ () => { // Éxito
+ uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
+ url = downloadURL;
+ console.log("Imagenes cargadas");
+ swal('Éxito', 'Imagenes cargadas con exito', 'success');
+ this.urlImgs = url;
+ });
+ }
+ );
+ }
+ }
+
+ // Deja los campos de usuario en blanco
+ resetUser(){
+ this.profile = {
+ uid: '',
+ rut: '',
+ name: '',
+ last_name1: '',
+ last_name2: '',
+ email: [],
+ phone: '',
+ categories: [],
+ commune: '',
+ status: true,
+ img: ''
+ };
+ }
+
+}
+
+ <div class="container">
+ <div class="row card">
+ <!-- ================================================================================================== -->
+ <!-- Profile options -->
+ <!-- ================================================================================================== -->
+ <ul class="nav nav-tabs customtab" role="tablist">
+ <li class="nav-item">
+ <a class="nav-link" data-toggle="tab" role="tab" aria-expanded="true"
+ [ngClass]="{'active': profile_options === 'my_profile'}"
+ (click)="profile_options = 'my_profile'">
+ <span class="hidden-xs-down">Mi perfil</span>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" data-toggle="tab" role="tab" aria-expanded="true"
+ [ngClass]="{'active': profile_options === 'edit_profile'}"
+ (click)="profile_options = 'edit_profile'">
+ <span class="hidden-xs-down">Editar perfil</span>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" data-toggle="tab" role="tab" aria-expanded="true"
+ [ngClass]="{'active': profile_options === 'preference_profile'}"
+ (click)="profile_options = 'preference_profile'">
+ <span class="hidden-xs-down">Preferencias de entrega</span>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" data-toggle="tab" role="tab" aria-expanded="true"
+ [ngClass]="{'active': profile_options === 'delete_profile'}"
+ (click)="profile_options = 'delete_profile'">
+ <span class="hidden-xs-down">Eliminar cuenta</span>
+ </a>
+ </li>
+ </ul>
+ <!-- ================================================================================================== -->
+ <!-- End profile options -->
+ <!-- ================================================================================================== -->
+
+
+ <div [ngSwitch]="profile_options">
+ <!-- ============================================================================================== -->
+ <!-- Show profile -->
+ <!-- ============================================================================================== -->
+ <div *ngSwitchCase="'my_profile'">
+ <div class="col-12">
+ <div class="card">
+ <div class="card-body row">
+ <div class="col-md-6" align="center">
+ <img [src]="profile.img" class="img-circle" width="300" />
+ <h4 class="card-title">
+ {{ profile.name | titlecase }} {{ profile.last_name1 | titlecase }} {{ profile.last_name2 | titlecase }} </h4>
+ <div class="row text-center justify-content-md-center">
+ <div class="col-4">
+ <a href="javascript:void(0)" class="link">
+ <i class="fa fa-book"></i>
+ <font class="font-medium"> {{ count_book }}</font>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <small class="text-muted">Correo electrónico</small>
+ <h6>{{ profile.email }}</h6>
+ <small class="text-muted p-t-30 db">Teléfono de contacto</small>
+ <h6>{{ profile.phone }}</h6>
+ <small class="text-muted p-t-30 db">Usuario creado el</small>
+ <h6>{{ profile.created_date }}</h6>
+ </div>
+ </div>
+ <!-- TODO: Revisar que esté aparezcan todas las cat. Copiar en modal de cardbook -->
+ <div class="card-body">
+ <small class="text-muted">Categorías favoritas:</small>
+ <ul>
+ <li>
+ <h6 *ngFor="let c of profile.categories">{{ c }}</h6>
+ </li>
+ </ul>
+ </div>
+
+ <div class="card-body">
+ <div class="dropdown-divider"></div>
+ <small class="text-muted p-t-30 db">Redes sociales</small><br/>
+ <button class="btn btn-circle btn-secondary" style="margin-left: 15px;"><i class="fa fa-facebook"></i></button>
+ <button class="btn btn-circle btn-secondary" style="margin-left: 15px;"><i class="fa fa-twitter"></i></button>
+ <button class="btn btn-circle btn-secondary" style="margin-left: 15px;"><i class="fa fa-youtube"></i></button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================================================== -->
+ <!-- End show profile -->
+ <!-- ============================================================================================== -->
+
+ <!-- ============================================================================================== -->
+ <!-- Edit profile -->
+ <!-- ============================================================================================== -->
+ <div *ngSwitchCase="'edit_profile'">
+ <div style="background-color: #FFFFFF;" class="tab-pane active" role="tabpanel" aria-expanded="true">
+ <div class="card-body">
+ <form class="form-horizontal form-material">
+ <div class="form-group">
+ <label class="col-md-12">Nombres</label>
+ <div class="col-md-12">
+ <input type="text" [(ngModel)]="profile.name" name="name" class="form-control form-control-line">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-md-12">Apellido Paterno</label>
+ <div class="col-md-12">
+ <input type="text" [(ngModel)]="profile.last_name1" name="last_name1" class="form-control form-control-line">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-md-12">Apellido Materno</label>
+ <div class="col-md-12">
+ <input type="text" [(ngModel)]="profile.last_name2" name="last_name2" class="form-control form-control-line">
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="example-email" class="col-md-12">Correo electrónico</label>
+ <div class="col-md-12">
+ <input type="email" [(ngModel)]="profile.email" name="email" class="form-control form-control-line">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-md-12">Teléfono de contacto</label>
+ <div class="col-md-12">
+ <input type="text" [(ngModel)]="profile.phone" name="phone" class="form-control form-control-line">
+ </div>
+ </div>
+
+ <div class="form-group col-md-12">
+ <input type="file" (change)="uploadFile($event)" id="file">
+ </div>
+
+ <div class="form-group">
+ <div class="col-sm-12">
+ <button type="button" class="btn btn-outline-info btn-block" (click)="updateProfile()">Editar</button>
+ </div>
+ </div>
+
+ </form>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================================================== -->
+ <!-- End edit profile -->
+ <!-- ============================================================================================== -->
+
+ <!-- ============================================================================================== -->
+ <!-- User preferences -->
+ <!-- ============================================================================================== -->
+ <div *ngSwitchCase="'preference_profile'">
+ <div style="background-color: #FFFFFF;" class="tab-pane active" id="settings" role="tabpanel" aria-expanded="true">
+ <div class="card-body">
+ <div class="table-responsive">
+ <table class="table color-table info-table">
+ <thead>
+ <tr>
+ <th>Estación de metro</th>
+ <th>Día</th>
+ <th>Horario</th>
+ <th class="text-nowrap">Acción</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let p of preferences; let i = index;">
+ <td> {{ p.subway_station }} </td>
+ <td> {{ p.day }} </td>
+ <td> {{ p.hour }} </td>
+ <td class="text-nowrap">
+ <!-- TODO: Falta hacer que esto funcione -->
+ <a data-toggle="modal" data-target="#editPreferences" (click)="preferences_modal = p">
+ <i class="fa fa-pencil text-inverse m-r-10"></i>
+ </a>
+ <a data-toggle="modal" data-target="#deletePreferences" (click)="deletePreference(i)">
+ <i class="fa fa-close text-danger"></i>
+ </a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <button type="button"
+ class="btn btn-outline-info"
+ data-toggle="modal"
+ data-target="#addPreferences">Agregar nueva preferencia</button>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================================================== -->
+ <!-- End user preferences -->
+ <!-- ============================================================================================== -->
+
+ <!-- ============================================================================================== -->
+ <!-- Delete user account -->
+ <!-- ============================================================================================== -->
+ <div *ngSwitchCase="'delete_profile'">
+ <div style="background-color: #FFFFFF;" class="tab-pane active" id="settings" role="tabpanel" aria-expanded="true">
+ <div class="card-body">
+ <p>Estás por eliminar tu cuenta de BOOKscalo. Tus datos, tu perfil público y las publicaciones que realizaste ya no podrán ser vistas por ti, ni por ningún otro usuario.
+ </p>
+ <p>Además debes considerar:</p>
+ <ul>
+ <li type="circle">Si solo quieres cambiar tus datos, no es necesario que desactives tu cuenta; modifícala en "Editar perfil".</li>
+ <li type="circle">Si solo quieres eliminar o editar una o todas tus publicaciones, no es necesario que desactives tu cuenta; elimínalos o edítalos en "Mi Biblioteca".</li>
+ <li type="circle">No podrás crear otra cuenta con el mismo correo con que iniciaste esta cuenta.</li>
+ </ul>
+ <button type="button" class="btn waves-effect waves-light btn-block btn-danger" (click)="deleteAccount()">
+ <i class="fa fa-warning"></i> Eliminar cuenta</button>
+ </div>
+ </div>
+ </div>
+ <!-- ============================================================================================== -->
+ <!-- End delete user account -->
+ <!-- ============================================================================================== -->
+ </div>
+ </div>
+</div>
+
+<!-- ================================================================================================== -->
+<!-- Modal add preferences -->
+<!-- ================================================================================================== -->
+<div id="addPreferences" class="modal fade bs-example-modal-lg">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myLargeModalLabel"> Agregar nueva preferencia de transacción </h4>
+ <button _ngcontent-c0="" aria-label="Close" class="close" data-dismiss="modal" type="button">
+ <span _ngcontent-c0="" aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <form class="form-material m-t-40" [formGroup]="form" (ngSubmit)="addPreference()">
+ <div class="row">
+ <!-- Inicio col 1 -->
+ <div class="form-group col-12">
+ <label>Estación de metro</label>
+ <select formControlName="subway_station" id="subway_station" class="form-control">
+ <optgroup label="Línea 1">
+ <option value="República">República</option>
+ <option value="Los Héroes">Los Héroes</option>
+ <option value="La Moneda">La Moneda</option>
+ <option value="Universidad de Chile">Universidad de Chile</option>
+ <option value="Santa Lucía">Santa Lucía</option>
+ <option value="Universidad Católica">Universidad Católica</option>
+ <option value="Baquedano">Baquedano</option>
+ <option value="Salvador">Salvador</option>
+ <option value="Manuel Montt">Manuel Montt</option>
+ <option value="Pedro de Valdivia">Pedro de Valdivia</option>
+ <option value="Los Leones">Los Leones</option>
+ <option value="Tobalaba">Tobalaba</option>
+ </optgroup>
+ <optgroup label="Línea 5">
+ <option value="Quinta Normal">Quinta Normal</option>
+ <option value="Cumming">Cumming</option>
+ <option value="Santa Ana">Santa Ana</option>
+ <option value="Plaza de Armas">Plaza de Armas</option>
+ <option value="Bellas Artes">Bellas Artes</option>
+ <option value="Baquedano">Baquedano</option>
+ <option value="Parque Bustamante">Parque Bustamante</option>
+ <option value="Santa Isabel">Santa Isabel</option>
+ </optgroup>
+ </select>
+ </div>
+ <div class="form-group col-md-6">
+ <label>Tipo de elemento</label>
+ <select formControlName="day" id="day" class="form-control">
+ <option value="Lunes">Lunes</option>
+ <option value="Martes">Martes</option>
+ <option value="Miércoles">Miércoles</option>
+ <option value="Jueves">Jueves</option>
+ <option value="Viernes">Viernes</option>
+ <option value="Sábado">Sábado</option>
+ <option value="Domingo">Domingo</option>
+ </select>
+ </div>
+
+ <div class="form-group col-md-6">
+ <label>Hora</label>
+ <input formControlName="hour" class="form-control" type="time" value="12:00" id="hour">
+ </div>
+ </div>
+ </form>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-outline-info" data-dismiss="modal" (click)="addPreference()">Agregar</button>
+ <button type="button" class="btn btn-danger waves-effect text-left" data-dismiss="modal">Cerrar</button>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- ================================================================================================== -->
+<!-- End modal add preferences -->
+<!-- ================================================================================================== -->
+
+
+<!-- ================================================================================================== -->
+<!-- Modal edit preferences -->
+<!-- ================================================================================================== -->
+<div id="editPreferences" class="modal fade bs-example-modal-lg">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myLargeModalLabel"> Editar preferencia de transacción </h4>
+ <button _ngcontent-c0="" aria-label="Close" class="close" data-dismiss="modal" type="button">
+ <span _ngcontent-c0="" aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <form class="form-material m-t-40" >
+ <div class="row">
+ <!-- Inicio col 1 -->
+ <div class="form-group col-12">
+ <label>Estación de metro</label>
+ <select name="subway_station" [(ngModel)]="preferences_modal.subway_station" class="form-control">
+ <optgroup label="Línea 1">
+ <option value="República">República</option>
+ <option value="Los Héroes">Los Héroes</option>
+ <option value="La Moneda">La Moneda</option>
+ <option value="Universidad de Chile">Universidad de Chile</option>
+ <option value="Santa Lucía">Santa Lucía</option>
+ <option value="Universidad Católica">Universidad Católica</option>
+ <option value="Baquedano">Baquedano</option>
+ <option value="Salvador">Salvador</option>
+ <option value="Manuel Montt">Manuel Montt</option>
+ <option value="Pedro de Valdivia">Pedro de Valdivia</option>
+ <option value="Los Leones">Los Leones</option>
+ <option value="Tobalaba">Tobalaba</option>
+ </optgroup>
+ <optgroup label="Línea 5">
+ <option value="Quinta Normal">Quinta Normal</option>
+ <option value="Cumming">Cumming</option>
+ <option value="Santa Ana">Santa Ana</option>
+ <option value="Plaza de Armas">Plaza de Armas</option>
+ <option value="Bellas Artes">Bellas Artes</option>
+ <option value="Baquedano">Baquedano</option>
+ <option value="Parque Bustamante">Parque Bustamante</option>
+ <option value="Santa Isabel">Santa Isabel</option>
+ </optgroup>
+ </select>
+ </div>
+ <div class="form-group col-md-6">
+ <label>Tipo de elemento</label>
+ <select name="day" [(ngModel)]="preferences_modal.day" class="form-control">
+ <option value="Lunes">Lunes</option>
+ <option value="Martes">Martes</option>
+ <option value="Miércoles">Miércoles</option>
+ <option value="Jueves">Jueves</option>
+ <option value="Viernes">Viernes</option>
+ <option value="Sábado">Sábado</option>
+ <option value="Domingo">Domingo</option>
+ </select>
+ </div>
+
+ <div class="form-group col-md-6">
+ <label>Hora</label>
+ <input type="email" name="hour" [(ngModel)]="preferences_modal.hour" class="form-control form-control-line" type="time" value="12:00" id="hour">
+ </div>
+ </div>
+ </form>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-outline-info" (click)="updateProfile()">Editar</button>
+ <button type="button" class="btn btn-danger waves-effect text-left" data-dismiss="modal">Cerrar</button>
+ </div>
+ </div>
+ </div>
+ </div>
+<!-- ================================================================================================== -->
+<!-- End modal edit preferences -->
+<!-- ================================================================================================== -->
+
+
+
+
+
+
+
+
+ +
+ src/app/register/register.component.ts
+
+
+ OnInit
+
selector | +app-register |
+
styleUrls | +./register.component.css |
+
templateUrl | +./register.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, _dateService: DateService, afAuth: AngularFireAuth, router: Router)
+ |
+ |||||||||||||||
+ Defined in src/app/register/register.component.ts:38
+ |
+ |||||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + addCategory + + + + | +||||||
+addCategory(index: number)
+ |
+ ||||||
+ Defined in src/app/register/register.component.ts:153
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + areEquals + + + + | +|||||||||
+areEquals(input1: string, input2: string)
+ |
+ |||||||||
+ Defined in src/app/register/register.component.ts:65
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ (group: any) => { areEquals: boolean; }
+
+
+
+
+ |
+
+ + + + getBackground + + + + | +||||||
+getBackground(page: string)
+ |
+ ||||||
+ Defined in src/app/register/register.component.ts:183
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ "url(../../assets/images/background/book-5.jpg)" | "url(../../assets/images/background/book-3.jpg...
+
+
+
+
+ |
+
+ + + + nextPage + + + + | +||||||
+nextPage(page: string)
+ |
+ ||||||
+ Defined in src/app/register/register.component.ts:167
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/register/register.component.ts:47
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + removeCategory + + + + | +||||||
+removeCategory(index: number)
+ |
+ ||||||
+ Defined in src/app/register/register.component.ts:161
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + saveUser + + + + | +
+saveUser()
+ |
+
+ Defined in src/app/register/register.component.ts:81
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + categories + + + + | +
+ categories:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : CATEGORIES
+ |
+
+ Defined in src/app/register/register.component.ts:34
+ |
+
+ + + + form + + + + | +
+ form:
+ |
+
+ Type : FormGroup
+
+ |
+
+ Defined in src/app/register/register.component.ts:32
+ |
+
+ + + + register_pages + + + + | +
+ register_pages:
+ |
+
+ Type : string
+
+ |
+
+ Default value : "page_1"
+ |
+
+ Defined in src/app/register/register.component.ts:33
+ |
+
+ + + + Public + router + + + + | +
+ router:
+ |
+
+ Type : Router
+
+ |
+
+ Defined in src/app/register/register.component.ts:43
+ |
+
+ + + + selected_categories + + + + | +
+ selected_categories:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/register/register.component.ts:35
+ |
+
+ + + + submit1 + + + + | +
+ submit1:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : false
+ |
+
+ Defined in src/app/register/register.component.ts:36
+ |
+
+ + + + submit2 + + + + | +
+ submit2:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : false
+ |
+
+ Defined in src/app/register/register.component.ts:37
+ |
+
+ + + + submit3 + + + + | +
+ submit3:
+ |
+
+ Type : boolean
+
+ |
+
+ Default value : false
+ |
+
+ Defined in src/app/register/register.component.ts:38
+ |
+
import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormControl, Validators, FormControlName } from '@angular/forms';
+import { Router } from '@angular/router';
+
+// INTERFACE
+import { Users } from "../interface/books.interface";
+
+// SERVICES
+import { DatabaseService } from "../services/database.service";
+import { DateService } from '../services/date.service';
+
+import { AngularFireAuth } from 'angularfire2/auth';
+
+// Sweet Alert
+import swal from 'sweetalert';
+
+// Data
+import { CATEGORIES } from '../../data/categories.data';
+import * as firebase from 'firebase';
+
+// Inicializa los plugins
+declare function init_plugins();
+
+@Component({
+ selector: 'app-register',
+ templateUrl: './register.component.html',
+ styleUrls: ['./register.component.css']
+
+})
+export class RegisterComponent implements OnInit {
+
+ form:FormGroup;
+ register_pages:string = "page_1"; //Muestra la primera página del registro por defecto
+ categories:any[] = CATEGORIES;
+ selected_categories:any[] = [];
+ submit1:boolean = false;
+ submit2:boolean = false;
+ submit3:boolean = false;
+
+ constructor( private _dbService:DatabaseService,
+ private _dateService:DateService,
+ private afAuth: AngularFireAuth,
+ public router: Router ) {
+ if( JSON.parse(localStorage.getItem('session')).session ) router.navigate(['/']);
+ }
+
+ ngOnInit() {
+ init_plugins();
+ this.form = new FormGroup({
+ name: new FormControl(undefined, [Validators.required, Validators.pattern("^([A-Za-z ,.'ñáéíóú]{2,20})$"), Validators.minLength(2)]),
+ last_name1: new FormControl(undefined, [Validators.required, Validators.pattern("^([A-Za-z ,.'ñáéíóú]{2,20})$"), Validators.minLength(2)]),
+ last_name2: new FormControl(undefined, [Validators.required, Validators.pattern("^([A-Za-z ,.'ñáéíóú]{2,20})$"), Validators.minLength(2)]),
+ rut: new FormControl(undefined, [Validators.required, Validators.pattern('^[.0-9]{6,11}\-?[kK0-9]{1}$')]),
+ // phone: new FormControl('', [Validators.pattern('^[0-9]{8}$'), Validators.minLength(8), Validators.maxLength(8)]),
+ // TODO: Validar los géneros
+ categories: new FormControl([], Validators.required),
+ email: new FormControl(undefined, [Validators.required, Validators.email, Validators.minLength(8)]),
+ password: new FormControl(undefined, Validators.required),
+ password2: new FormControl(undefined, Validators.required),
+ conditions: new FormControl(false, Validators.required),
+ }, { validators: this.areEquals( 'password', 'password2') });
+ }
+
+ // Verifica que ambas contraseñas ingresadas sean iguales
+ areEquals(input1:string, input2:string){
+ return (group: FormGroup) => {
+ let pass1 = group.controls[input1].value;
+ let pass2 = group.controls[input2].value;
+
+ if( pass1 === pass2 ){
+ return null;
+ }
+
+ return {
+ areEquals: true
+ }
+ }
+ }
+
+ // Guarda un usuario nuevo, en DB
+ saveUser(){
+
+ this.submit1 = true;
+ this.submit2 = true;
+ this.submit3 = true;
+
+ if (this.form.valid) {
+ let form=this.form.value;
+
+ this.afAuth.auth.createUserWithEmailAndPassword( form.email, form.password )
+ .then( (resp:any) => {
+
+ // FIXME: Esto hace que se seleccione un emoji aleatorio para la imagen del nuevo usuario.
+ let num = Math.floor((Math.random() * 47) + 1);
+ let path_img = "../assets/images/emojis/emoji("+num+").png";
+ console.log(path_img);
+
+ // Guarda el form para validarlo
+ const USER:Users = {
+ uid: resp.user.uid,
+ rut: form.rut,
+ name: form.name.toLowerCase(),
+ last_name1: form.last_name1.toLowerCase(),
+ last_name2: form.last_name2.toLowerCase(),
+ email: form.email.toLowerCase(),
+ categories: this.selected_categories,
+ // phone: form.phone,
+ firtSession: false,
+ google: false,
+ status: true,
+ role: 'normal',
+ created_date: this._dateService.actual_date(),
+ img: path_img
+ };
+
+ if( !this.form.value.conditions ){
+ swal("Importante", "Debe aceptar los términos y condiciones", "warning");
+ return;
+ }
+
+ // Guarda al usuario en DB
+ this._dbService.addDataIdCustom('users', USER.uid, USER)
+ .then( () => {
+ console.log("Se guardó el usuario");
+ swal('Cuenta creada con éxito', USER.email, 'success');
+ this.afAuth.auth.signOut();
+ this.router.navigate([ '/login' ]);
+
+ // Envía un correo de verificación al usuario que se acaba de registrar
+ var user = firebase.auth().currentUser;
+ user.sendEmailVerification().then(function() {
+ console.log("Email de verificación enviado")
+ }).catch(function(error) {
+ console.log("No se ha podido enviar el email de verificación enviado")
+ });
+
+ })
+ .catch( (err) => {
+ console.log("Error al guardar al usuario", err);
+ swal("Error", "No se ha podido guardar el nuevo usuario", "warning");
+ })
+ })
+ .catch( (err) => console.error('ERROR: Crear usuario en firebase', err) );
+ }else{
+ swal("Error", "Debe llenar todos los campos del formulario", "warning");
+ }
+
+
+ }
+
+ // FIXME: Revisar porque al parecer esto se está haciendo al revés
+ // Agrega una categoría al cuadro de categorías favoritas del usuario
+ addCategory(index:number){
+ this.selected_categories.push(this.categories[index]);
+ this.categories.splice(index, 1);
+ // TODO: Ordenar por index
+ }
+
+ // FIXME: Revisar porque al parecer esto se está haciendo al revés
+ // Remueve una categoría del cuadro de categorías favoritas del usuario
+ removeCategory(index:number){
+ this.categories.push(this.selected_categories[index]);
+ this.selected_categories.splice(index, 1);
+ }
+
+
+ nextPage(page:string){
+ let form = this.form;
+ switch( page ) {
+ case 'page_2':
+ this.submit1 = true;
+ if( form.controls['name'].valid && form.controls['last_name1'].valid && form.controls['last_name2'].valid && form.controls['rut'].valid)
+ this.register_pages = 'page_2';
+ break;
+ case 'page_3':
+ this.submit2 = true;
+ if( this.selected_categories.length >= 3 )
+ this.register_pages = 'page_3';
+ break;
+ }
+ }
+ // Cambia el fondo del register dependiendo de en qué etapa se encuentre
+ getBackground(page:string) {
+ switch (page) {
+ case 'page_1':
+ return 'url(../../assets/images/background/book-5.jpg)';
+ case 'page_2':
+ return 'url(../../assets/images/background/book-3.jpg)';
+ case 'page_3':
+ return 'url(../../assets/images/background/book-1.jpg)';
+ }
+ }
+}
+
+ <section id="wrapper">
+ <div class="login-register" [ngStyle]="{'background-image':getBackground(register_pages)}" >
+ <div class="login-box card">
+ <div class="card-body" >
+ <form class="form-horizontal form-material" novalidate="novalidate" action="index.html"
+ [formGroup]="form" (ngSubmit)="saveUser()">
+
+ <div [ngSwitch]="register_pages">
+ <!-- ================================================================== -->
+ <!-- PAGE 1 -->
+ <!-- ================================================================== -->
+ <div *ngSwitchCase="'page_1'">
+ <h3 class="box-title m-b-40">Datos de perfil</h3>
+ <small>Crea tu cuenta para ingresar</small>
+
+ <div class="form-group m-t-20">
+ <div class="col-xs-12">
+ <input formControlName="name" class="form-control" type="text" placeholder="Nombre">
+ </div>
+ <div *ngIf="form.controls['name'].errors?.required && submit1"><p class="text-danger">El nombre es requerido</p></div>
+ <div *ngIf="form.controls['name'].errors?.pattern && submit1"><p class="text-danger">El nombre ingresado no es válido</p></div>
+ </div>
+
+ <div class="form-group m-t-10 row">
+ <div class="col-md-6">
+ <input formControlName="last_name1" class="form-control" type="text" placeholder="Apellido paterno">
+ <div *ngIf="form.controls['last_name1'].errors?.required && submit1"><p class="text-danger">El apellido es requerido</p></div>
+ <div *ngIf="form.controls['last_name1'].errors?.pattern && submit1"><p class="text-danger">El apellido ingresado no es válido</p></div>
+ </div>
+ <div class="col-md-6">
+ <input formControlName="last_name2" class="form-control" type="text" placeholder="Apellido materno">
+ <div *ngIf="form.controls['last_name2'].errors?.required && submit1"><p class="text-danger">El apellido es requerido</p></div>
+ <div *ngIf="form.controls['last_name2'].errors?.pattern && submit1"><p class="text-danger">El apellido ingresado no es válido</p></div>
+ </div>
+ </div>
+
+ <div class="form-group m-t-20">
+ <div class="col-xs-12">
+ <input formControlName="rut" class="form-control" type="text" placeholder="RUT">
+ </div>
+ <div *ngIf="form.controls['rut'].errors?.required && submit1"><p class="text-danger">El RUT es requerido</p></div>
+ <div *ngIf="form.controls['rut'].errors?.pattern && submit1"><p class="text-danger">El RUT ingresado no es válido</p></div>
+ </div>
+
+ <!-- <div class="form-group m-t-20">
+ <div class="col-xs-12">
+ <input formControlName="phone" class="form-control" type="text" placeholder="Teléfono opcional">
+ </div>
+ <div *ngIf="form.controls['phone'].errors?.pattern && submit"><p class="text-danger">El teléfono ingresado no es válido</p></div>
+ </div> -->
+
+ <div class="form-group text-center m-t-20">
+ <div class="col-xs-12">
+ <button type="button" (click)="nextPage('page_2')"
+ class="btn btn-info btn-lg btn-block text-uppercase waves-effect waves-light">
+ Continuar
+ </button>
+ </div>
+ </div>
+
+ <div class="form-group m-b-0">
+ <div class="col-sm-12 ">
+ <button class="btn btn-circle btn-info" style="margin-right: 80px;" [routerLink]="['/login']">
+ <i class="fa fa-arrow-left"></i>
+ </button>
+ <p class="text-center" style="display: contents;">Ya tienes una cuenta?
+ <a [routerLink]="['/login']" class="text-info m-l-5">
+ <b>Ingresar</b>
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <!-- ================================================================================== -->
+ <!-- PAGE 2 -->
+ <!-- ================================================================================== -->
+ <div *ngSwitchCase="'page_2'">
+
+ <h3 class="box-title m-b-40">Categorías de interés <span>(Min. 3)</span></h3>
+ <div class="ms-container" id="ms-pre-selected-options">
+ <div class="ms-selectable">
+ <select class="ms-list contenedor" multiple='multiple' formControlName="categories">
+ <option [value]='c' class="ms-elem-selectable"
+ *ngFor="let c of categories; let i = index;"
+ (click)="addCategory(i)"> {{ c.name }} </option>
+ </select>
+ </div>
+ <div class="ms-selection">
+ <select class="ms-list contenedor" multiple='multiple' formControlName="categories">
+ <option [value]='sc' class="ms-elem-selection"
+ *ngFor="let sc of selected_categories; let i = index;"
+ (click)="removeCategory(i)"> {{ sc.name }} </option>
+ </select>
+ </div>
+ </div>
+ <p *ngIf="selected_categories.length < 3 && submit2" class="text-danger">
+ Debe seleccionar al menos 3 categorias
+ </p>
+
+ <div class="form-group text-center m-t-20">
+ <div class="col-xs-12">
+ <button type="button" (click)="nextPage('page_3')"
+ class="btn btn-info btn-lg btn-block text-uppercase waves-effect waves-light">
+ Continuar
+ </button>
+ </div>
+ </div>
+
+ <div class="form-group m-b-0">
+ <div class="col-sm-12 ">
+ <button class="btn btn-circle btn-info" style="margin-right: 80px;" (click)="register_pages='page_1'">
+ <i class="fa fa-arrow-left"></i>
+ </button>
+ <p class="text-center" style="display: contents;">Ya tienes una cuenta?
+ <a [routerLink]="['/login']" class="text-info m-l-5">
+ <b>Ingresar</b>
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <!-- ================================================================================== -->
+ <!-- PAGE 3 -->
+ <!-- ================================================================================== -->
+ <div *ngSwitchCase="'page_3'">
+
+ <h3 class="box-title m-b-40">Datos de la cuenta</h3>
+ <div class="form-group">
+ <div class="col-xs-12">
+ <input formControlName="email" class="form-control" type="text" placeholder="Correo electrónico">
+ </div>
+ <div *ngIf="form.controls['email'].errors?.required && submit3"><p class="text-danger">El email es requerido</p></div>
+ <div *ngIf="form.controls['email'].errors?.email && submit3"><p class="text-danger">El email ingresado no es válido</p></div>
+ </div>
+
+ <div class="form-group ">
+ <div class="col-xs-12">
+ <input formControlName="password" class="form-control" type="password" placeholder="Contraseña">
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="col-xs-12">
+ <input formControlName="password2" class="form-control" type="password" placeholder="Confirme su contraseña">
+ </div>
+ </div>
+
+ <div class="form-group" *ngIf="form['errors']?.areEquals && !form.pristine && submit3">
+ <p class="text-danger"> Las contraseñas deben ser iguales </p>
+ </div>
+
+ <div class="form-group row">
+ <div class="col-md-12">
+ <div class="checkbox checkbox-primary p-t-0">
+ <input formControlName="conditions" id="checkbox-signup" type="checkbox">
+ <label for="checkbox-signup"> Acepto los
+ <!-- TODO: Revisar -->
+ <a style="color:#398bf7;" data-toggle="modal" data-target="#conditionsOfUse">Términos y Condiciones de Uso</a>
+ </label>
+ </div>
+ </div>
+ </div>
+
+ <div class="form-group text-center m-t-20">
+ <div class="col-xs-12">
+ <button class="btn btn-info btn-lg btn-block text-uppercase waves-effect waves-light"
+ type="submit">
+ Registrarme
+ </button>
+ </div>
+ </div>
+
+ <div class="form-group m-b-0">
+ <div class="col-sm-12 ">
+ <button class="btn btn-circle btn-info" style="margin-right: 80px;" (click)="register_pages='page_2'">
+ <i class="fa fa-arrow-left"></i>
+ </button>
+ <p class="text-center" style="display: contents;">Ya tienes una cuenta?
+ <a [routerLink]="['/login']" class="text-info m-l-5">
+ <b>Ingresar</b>
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+</section>
+
+<!-- ================================================================================================== -->
+<!-- Modal Terms and Use Conditions -->
+<!-- ================================================================================================== -->
+<div id="conditionsOfUse" class="modal fade bs-example-modal-lg">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myLargeModalLabel"> Términos y Condiciones de uso </h4>
+ <button _ngcontent-c0="" aria-label="Close" class="close" data-dismiss="modal" type="button">
+ <span _ngcontent-c0="" aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <p><strong>INFORMACIÓN RELEVANTE</strong></p>
+ <p>
+ Es requisito necesario para la utilización de los servicios que presta este aplicativo web, que lea y acepte los siguientes Términos y Condiciones que a continuación se redactan. El uso de nuestros servicios así como la recepción de notificaciones implicará que usted ha leído y aceptado los Términos y Condiciones de Uso en el presente documento.
+ </p>
+ <p>
+ El usuario puede elegir y cambiar la clave para su acceso de administración de la cuenta en cualquier momento, en caso de que se haya registrado y que lo desee. BOOKscalo.com no asume la responsabilidad en caso de que entregue dicha clave a terceros.
+ </p>
+ <p>
+ Todos los acuerdos que se lleven a cabo por medio de este sitio web, están sujetas a un proceso de confirmación por parte de los involucrados. En algunos casos puede que se requiera una verificación por medio de correo electrónico.
+ </p>
+ <p>
+ Los precios de los libros y textos ofrecidos en este aplicativo web son de exclusiva responsabilidad del usuario que los publica, los cuales pueden modificarlos a su antojo.
+ </p>
+ <p>
+ En ningún caso esta compañía será responsable de ningún daño incluyendo, pero no limitado a, daños directos, indirectos, especiales,fortuitos o consecuentes u otras pérdidas resultantes de las reuniones que se realicen entre usuarios con el objetivo de concretar las transacciones de libros o textos publicitados en el sitio web.
+ </p>
+ <p>
+ El sitio web no está destinado al pago, transacciones monetarias, ni al envío de libros o textos a los usuarios finales. Toda transacción es exclusiva responsabilidad de los usuarios que realicen el establecimiento de transacción.
+ </p>
+ <p><strong>LICENCIA</strong></p>
+ <p>
+ BOOKscalo a través de su sitio web concede una licencia para que los usuarios publiquen los libros y textos que desean ofertar en este sitio web de acuerdo a los Términos y Condiciones que se describen en este documento.
+ </p>
+ <p><strong>PROPIEDAD</strong></p>
+ <p>
+ Usted no puede declarar propiedad intelectual o exclusiva a ninguno de los libros o textos publicados, modificado o sin modificar. Todos los libros o textos son propiedad de los proveedores del contenido. En caso de que no se especifique lo contrario, los libros o textos se proporcionan sin ningún tipo de garantía, expresa o implícita.
+ </p>
+ <p><strong>COMPROBACIÓN ANTIFRAUDE</strong></p>
+ <p>
+ La compra del cliente puede ser aplazada para la comprobación antifraude. También puede ser suspendida por más tiempo para una investigación más rigurosa, para evitar transacciones fraudulentas.
+ </p>
+ <p><strong>PRIVACIDAD</strong></p>
+ <p>
+ Este <a href="https://bookscalo.com" target="_blank">sitio web</a> BOOKscalo.com garantiza que la información personal que usted envía cuenta con la seguridad necesaria. Los datos ingresados por usuario no serán entregados a terceros, salvo que deba ser revelada en cumplimiento a una orden judicial o requerimientos legales.
+ </p>
+ <p>
+ La suscripción a boletines de correos electrónicos publicitarios es voluntaria y la suscripción a notificaciones también, las cuales podrá encontrar una vez ingrese al sitio web mediante sus credenciales, seleccionando la campana ubicada en la esquina inferior derecha.
+ </p>
+ <p>
+ BOOKscalo reserva los derechos de cambiar o de modificar estos términos sin previo aviso, aunque para su seguridad, los cambios serán notificados mediante notificaciones del administrador.
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- ================================================================================================== -->
+<!-- End modal Terms and Use Conditions -->
+<!-- ================================================================================================== -->
+
+
+
+ ./register.component.css
+
.login-register {
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: center center;
+ height: 160%;
+ width: 100%;
+ padding: 10% 0;
+ position: absolute; }
+
+.login-box {
+ width: 100%;
+ max-width: 580px;
+ margin: 0 auto; }
+ .login-box .footer {
+ width: 100%;
+ left: 0px;
+ right: 0px; }
+ .login-box .social {
+ display: block;
+ margin-bottom: 30px; }
+
+#recoverform {
+ display: none; }
+
+.login-sidebar {
+ padding: 0px;
+ margin-top: 0px; }
+ .login-sidebar .login-box {
+ right: 0px;
+ position: absolute;
+ height: 100%; }
+
+.contenedor {
+ max-width: 220px !important;
+ min-width: 220px !important;
+}
+
+.ms-container {
+ width: 100%;
+}
+
+ +
+ src/app/pages/search/search.component.ts
+
+
+ OnInit
+
selector | +app-search |
+
templateUrl | +./search.component.html |
+
+ Properties+ |
+
+ + | +
+ Methods+ |
+
+
|
+
+constructor(activatedRoute: ActivatedRoute, _dbService: DatabaseService)
+ |
+ |||||||||
+ Defined in src/app/pages/search/search.component.ts:16
+ |
+ |||||||||
+
+ Parameters :
+
+
|
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/pages/search/search.component.ts:21
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + searchAuthor + + + + | +|||||||||
+searchAuthor(books: any[], search: string)
+ |
+ |||||||||
+ Defined in src/app/pages/search/search.component.ts:59
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ {}
+
+
+
+
+ |
+
+ + + + searchBook + + + + | +|||||||||
+searchBook(books: any[], search: string)
+ |
+ |||||||||
+ Defined in src/app/pages/search/search.component.ts:47
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any[]
+
+
+
+
+ |
+
+ + + + searchOwner + + + + | +|||||||||
+searchOwner(users: any[], search: string)
+ |
+ |||||||||
+ Defined in src/app/pages/search/search.component.ts:71
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ {}
+
+
+
+
+ |
+
+ + + + searchSidebar + + + + | +|||||||||
+searchSidebar(books: any[], input: string)
+ |
+ |||||||||
+ Defined in src/app/pages/search/search.component.ts:83
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ {}
+
+
+
+
+ |
+
+ + + + authors + + + + | +
+ authors:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/pages/search/search.component.ts:13
+ |
+
+ + + + books + + + + | +
+ books:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/pages/search/search.component.ts:12
+ |
+
+ + + + owners + + + + | +
+ owners:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/pages/search/search.component.ts:14
+ |
+
+ + + + sidebar + + + + | +
+ sidebar:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/pages/search/search.component.ts:15
+ |
+
+ + + + typeInput + + + + | +
+ typeInput:
+ |
+
+ Type : string[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/pages/search/search.component.ts:16
+ |
+
import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+
+// SERVICES
+import { DatabaseService } from "../../services/database.service";
+
+@Component({
+ selector: 'app-search',
+ templateUrl: './search.component.html'
+})
+export class SearchComponent implements OnInit {
+ books:any[] = [];
+ authors:any[] = [];
+ owners:any[] = [];
+ sidebar:any[] = [];
+ typeInput:string[] = [];
+
+ constructor( private activatedRoute:ActivatedRoute,
+ private _dbService: DatabaseService ) { }
+
+ ngOnInit() {
+ this.activatedRoute.params.subscribe( params => {
+ const input:string = params['input'];
+ this.typeInput = input.split('.');
+
+
+ console.log(input);
+ this._dbService.getData('books')
+ .valueChanges()
+ .subscribe( resp => {
+ if( this.typeInput[0] === 'sidebar' ) {
+ this.sidebar = this.searchSidebar(resp, this.typeInput[1]);
+ }else {
+ this.books = this.searchBook(resp, input);
+ this.authors = this.searchAuthor(resp, input);
+ }
+ });
+
+ this._dbService.getData('users')
+ .valueChanges()
+ .subscribe( users => this.owners = this.searchOwner(users, input) );
+
+
+ });
+ }
+
+ searchBook(books:any[], search:string): any[]{
+ let searchBook = [];
+
+ for( let book of books ){
+ let title = book.title.toLowerCase();
+ if( title.indexOf(search.toLowerCase()) >= 0 ) {
+ searchBook.push(book);
+ }
+ }
+ return searchBook;
+ }
+
+ searchAuthor(books:any[], search:string){
+ let searchAuthor = [];
+
+ for( let book of books ){
+ let author = book.author.toLowerCase();
+ if( author.indexOf(search.toLowerCase()) >= 0 ) {
+ searchAuthor.push(book);
+ }
+ }
+ return searchAuthor;
+ }
+
+ searchOwner(users:any[], search:string) {
+ let owners = [];
+
+ for( let user of users ){
+ let owner = user.name;
+ if( owner.indexOf(search.toLowerCase()) >= 0 ) {
+ owners.push(user);
+ }
+ }
+ return owners;
+ }
+
+ searchSidebar(books:any[], input:string) {
+ let searchCategories = [];
+
+ for( let book of books ) {
+ let categories = book.genres;
+ let flag = false; // con esto valido que se agregue solo 1 vez el mismo libro
+
+ for( let category of categories ){
+ let cat = category.toLowerCase();
+
+ if( cat.indexOf(input.toLowerCase()) >= 0 && !flag ) {
+ flag = true;
+ searchCategories.push(book);
+ }
+ }
+ }
+ console.log(searchCategories);
+ return searchCategories;
+ }
+
+
+
+}
+
+ <div class="row" *ngIf="typeInput[0] !== 'sidebar'; else Sidebar">
+ <div class="card col-12 col-lg-4">
+ <div class="card-body">
+ <h4 class="card-title">Libros</h4>
+ <ul class="list-unstyled" *ngIf="books.length > 0; else noBooks;">
+ <li class="media border p-1" *ngFor="let book of books">
+ <img class="d-flex mr-3"
+ [src]="book.images[0]"
+ width="60">
+ <div class="media-body">
+ <h5 class="mt-0 mb-2"> {{ book.title }} </h5>
+ <h5 class="mt-0 mb-2">{{ book.author }}</h5>
+ <h5 class="mt-0 mb-2">{{ book.language }}</h5>
+ <h5 class="mt-0 mb-2" *ngIf="book.transaction === 'Ambos'"> Venta-Intercambio </h5>
+ <h5 class="mt-0 mb-2" *ngIf="book.transaction !== 'Ambos'"> {{ book.transaction }}</h5>
+ <h5 class="mt-0 mb-2 text-success" *ngIf="book.transaction === 'Ambos'"> ${{ book.price }} </h5>
+ <h5 class="mt-0 mb-2 text-success" *ngIf="book.transaction === 'Venta'"> ${{ book.price }} </h5>
+ </div>
+ </li>
+ </ul>
+
+ <ng-template #noBooks>
+ <div class="alert alert-primary" role="alert">
+ No se encontraron coincidencias
+ </div>
+ </ng-template>
+
+ </div>
+ </div>
+ <div class="card col-12 col-lg-4">
+ <div class="card-body">
+ <h4 class="card-title">Autores</h4>
+ <ul class="list-unstyled" *ngIf="authors.length > 0; else noAuth;">
+ <li class="media media border p-1" *ngFor="let auth of authors">
+ <img class="d-flex mr-3"
+ [src]="auth.images[0]"
+ width="60">
+ <div class="media-body">
+ <h5 class="mt-0 mb-2"> {{ auth.author }} </h5>
+ <h5 class="mt-0 mb-2"> {{ auth.title }} </h5>
+ </div>
+ </li>
+ </ul>
+
+ <ng-template #noAuth>
+ <div class="alert alert-primary" role="alert">
+ No se encontraron coincidencias
+ </div>
+ </ng-template>
+ </div>
+ </div>
+
+ <div class="card col-12 col-lg-4">
+ <div class="card-body">
+ <h4 class="card-title">Dueños</h4>
+ <ul class="list-unstyled" *ngIf="owners.length > 0; else noOwner">
+ <li class="media media border p-1" *ngFor="let cat of sidebar">
+ <img class="d-flex mr-3"
+ [src]="cat.img"
+ width="60">
+ <div class="media-body">
+ <h5 class="mt-0 mb-2">{{ cat.name }}</h5>
+ <h5 class="mt-0 mb-2"> {{ cat.last_name1 }} {{ cat.last_name2 }} </h5>
+ </div>
+ </li>
+ </ul>
+
+ <ng-template #noOwner>
+ <div class="alert alert-primary" role="alert">
+ No se encontraron coincidencias
+ </div>
+ </ng-template>
+ </div>
+ </div>
+</div>
+
+
+
+
+
+
+
+<ng-template #Sidebar>
+ <div class="card col-12">
+ <div class="card-body">
+ <h4 class="card-title">Búsqueda por categoría: {{ typeInput[1] }}</h4>
+ <ul class="list-unstyled" *ngIf="sidebar.length > 0; else noSidebar">
+ <li class="media media border p-1" *ngFor="let cat of sidebar">
+ <img class="d-flex mr-3"
+ [src]="cat.images[0]"
+ width="60">
+ <div class="media-body">
+ <h5 class="mt-0 mb-2"> {{ cat.title }} </h5>
+ <h5 class="mt-0 mb-2">{{ cat.author }}</h5>
+ <h5 class="mt-0 mb-2">{{ cat.language }}</h5>
+ <h5 class="mt-0 mb-2" *ngIf="cat.transaction === 'Ambos'"> Venta-Intercambio </h5>
+ <h5 class="mt-0 mb-2" *ngIf="cat.transaction !== 'Ambos'"> {{ cat.transaction }}</h5>
+ <h5 class="mt-0 mb-2 text-success" *ngIf="cat.transaction === 'Ambos'"> ${{ cat.price }} </h5>
+ <h5 class="mt-0 mb-2 text-success" *ngIf="cat.transaction === 'Venta'"> ${{ cat.price }} </h5>
+ <hr>
+ <h5 class="mt-0 mb-2"> Otras categorías a las que pertenece </h5>
+ <h6 class="mt-0 mb-2" *ngFor="let genres of cat.genres"> {{ genres }} </h6>
+ </div>
+ </li>
+ </ul>
+
+ <ng-template #noSidebar>
+ <div class="alert alert-primary" role="alert">
+ no se encontraron coincidencias
+ </div>
+ </ng-template>
+ </div>
+ </div>
+</ng-template>
+ +
+ src/app/shared/sidebar/sidebar.component.ts
+
+
+ OnInit
+
selector | +app-sidebar |
+
templateUrl | +./sidebar.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService, router: Router, _sidebar: SidebarService)
+ |
+ ||||||||||||
+ + | +||||||||||||
+
+ Parameters :
+
+
|
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ + + + searchCategory + + + + | +||||||
+searchCategory(search: string)
+ |
+ ||||||
+ + | +||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ void
+
+
+
+
+ |
+
+ + + + books + + + + | +
+ books:
+ |
+
+ Type : any
+
+ |
+
+ + | +
+ + + + categories + + + + | +
+ categories:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : CATEGORIES
+ |
+
+ + | +
+ + + + menu + + + + | +
+ menu:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ + | +
+ + + + role + + + + | +
+ role:
+ |
+
+ Type : string
+
+ |
+
+ + | +
import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+
+import { CATEGORIES } from '../../../data/categories.data';
+
+// SERVICES
+import { DatabaseService } from 'src/app/services/database.service';
+import { SidebarService } from '../../services/sidebar.service';
+
+@Component({
+ selector: 'app-sidebar',
+ templateUrl: './sidebar.component.html'
+})
+export class SidebarComponent implements OnInit {
+
+ books:any;
+
+ menu:any=[];
+ categories:any[] = CATEGORIES;
+ role:string;
+
+ constructor( private _dbService:DatabaseService,
+ private router: Router,
+ private _sidebar:SidebarService ) {
+ this.menu = this._sidebar.menu;
+ this.role = JSON.parse(localStorage.getItem("user")).role;
+ }
+
+ ngOnInit() {
+ this._dbService.getData('books')
+ .valueChanges()
+ .subscribe( data => this.books = data );
+ }
+
+ // Busca los libros según el search, que es la categoría.
+ searchCategory( search:string ){
+ let searchCategories = [];
+
+ for( let book of this.books ) {
+ let categories = book.genres;
+ let flag = false; // con esto valido que se agregue solo 1 vez el mismo libro
+
+ for( let category of categories ){
+ let cat = category.toLowerCase();
+
+ if( cat.indexOf(search.toLowerCase()) >= 0 && !flag ) {
+ flag = true;
+ searchCategories.push(book);
+ }
+ }
+ }
+ this.router.navigate(['/search', search]);
+ }
+
+}
+
+ <aside class="left-sidebar">
+ <div class="scroll-sidebar">
+ <nav class="sidebar-nav">
+ <ul id="sidebarnav">
+ <li class="nav-small-cap" *ngIf="role === 'normal'">CATEGORÍAS</li>
+ <li class="nav-small-cap" *ngIf="role === 'admin'">MENÚ</li>
+ <li class="nav-devider"></li>
+ <li class="nav-small-cap"
+ routerLinkActive="active"
+ style="cursor: pointer;"
+ *ngFor="let m of menu">
+ <a *ngIf="role === 'normal'" [routerLink]="['/search', 'sidebar.'+m.name]"> {{ m.name }} </a>
+ <a *ngIf="role === 'admin'" [routerLink]=[m.route]> {{ m.name }} </a>
+ </li>
+ </ul>
+ </nav>
+ </div>
+</aside>
+ +
+ src/app/admin/users/users.component.ts
+
+
+ OnInit
+
selector | +app-users |
+
styleUrls | +./users.component.css |
+
templateUrl | +./users.component.html |
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor(_dbService: DatabaseService)
+ |
+ ||||||
+ Defined in src/app/admin/users/users.component.ts:13
+ |
+ ||||||
+
+ Parameters :
+
+
|
+
+ + + + ngOnInit + + + + | +
+ngOnInit()
+ |
+
+ Defined in src/app/admin/users/users.component.ts:21
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + users + + + + | +
+ users:
+ |
+
+ Type : any
+
+ |
+
+ Defined in src/app/admin/users/users.component.ts:13
+ |
+
import { Component, OnInit } from '@angular/core';
+
+// SERVICES
+import { DatabaseService } from '../../services/database.service';
+
+@Component({
+ selector: 'app-users',
+ templateUrl: './users.component.html',
+ styleUrls: ['./users.component.css']
+})
+export class UsersComponent implements OnInit {
+
+ users:any;
+
+ constructor( private _dbService:DatabaseService) {
+ this._dbService.getData( "users")
+ .valueChanges()
+ .subscribe( data => this.users = data );
+ }
+
+ ngOnInit() {
+ }
+
+}
+
+ <!-- ============================================================== -->
+<!-- All users -->
+<!-- ============================================================== -->
+<h1>Usuarios</h1>
+<div class="row">
+ <div class="col-md-6 col-lg-6 col-xlg-4" *ngFor="let u of users">
+ <div class="card card-body">
+ <div class="row">
+ <div class="col-md-4 col-lg-3 text-center">
+ <img [src]="u.img" alt="user" class="img-circle img-responsive">
+ </div>
+ <div class="col-md-8 col-lg-9">
+ <h3 class="box-title m-b-0">{{ u.name | titlecase }} {{ u.last_name1 | titlecase }} {{ u.last_name2 | titlecase }}</h3>
+ <small>{{ u.rut }}</small>
+ <br/>
+ <address>
+ {{ u.email }}
+ <br/>
+ <abbr title="Phone">P:</abbr> (+56 9) {{ u.phone }}
+ </address>
+ <small class="text-muted">Creado el: {{ u.created_date }}</small>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- ============================================================== -->
+<!-- End all users -->
+<!-- ============================================================== -->
+
+ ./users.component.css
+
+ File | +Type | +Identifier | +Statements | +
---|---|---|---|
+ + src/app/admin/admin.component.ts + | ++ component + | ++ AdminComponent + | ++ 0 % + (0/3) + | +
+ + src/app/admin/admin.component.ts + | ++ function + | ++ init_plugins + | ++ 0 % + (0/1) + | +
+ + src/app/admin/admin.routes.ts + | ++ variable + | ++ ADMIN_ROUTES + | ++ 0 % + (0/1) + | +
+ + src/app/admin/dashboard/dashboard.component.ts + | ++ component + | ++ DashboardComponent + | ++ 0 % + (0/17) + | +
+ + src/app/admin/global-message/global-message.component.ts + | ++ component + | ++ GlobalMessageComponent + | ++ 0 % + (0/14) + | +
+ + src/app/admin/users/users.component.ts + | ++ component + | ++ UsersComponent + | ++ 0 % + (0/4) + | +
+ + src/app/app.component.ts + | ++ component + | ++ AppComponent + | ++ 0 % + (0/2) + | +
+ + src/app/app.routes.ts + | ++ variable + | ++ APP_ROUTES + | ++ 0 % + (0/1) + | +
+ + src/app/components/card-book/card-book.component.ts + | ++ component + | ++ CardBookComponent + | ++ 0 % + (0/16) + | +
+ + src/app/components/loading/loading.component.ts + | ++ component + | ++ LoadingComponent + | ++ 0 % + (0/3) + | +
+ + src/app/components/one-book/one-book.component.ts + | ++ component + | ++ OneBookComponent + | ++ 0 % + (0/5) + | +
+ + src/app/interface/books.interface.ts + | ++ interface + | ++ Books + | ++ 0 % + (0/18) + | +
+ + src/app/interface/books.interface.ts + | ++ interface + | ++ Message + | ++ 0 % + (0/10) + | +
+ + src/app/interface/books.interface.ts + | ++ interface + | ++ Report + | ++ 0 % + (0/9) + | +
+ + src/app/interface/books.interface.ts + | ++ interface + | ++ Users + | ++ 0 % + (0/16) + | +
+ + src/app/pageforbidden/pageforbidden.component.ts + | ++ component + | ++ PageforbiddenComponent + | ++ 0 % + (0/3) + | +
+ + src/app/pageforbidden/pageforbidden.component.ts + | ++ function + | ++ init_plugins + | ++ 0 % + (0/1) + | +
+ + src/app/pagenotfound/pagenotfound.component.ts + | ++ component + | ++ PagenotfoundComponent + | ++ 0 % + (0/3) + | +
+ + src/app/pagenotfound/pagenotfound.component.ts + | ++ function + | ++ init_plugins + | ++ 0 % + (0/1) + | +
+ + src/app/pages/add-book/add-book.component.ts + | ++ component + | ++ AddBookComponent + | ++ 0 % + (0/14) + | +
+ + src/app/pages/chats/chats.component.ts + | ++ component + | ++ ChatsComponent + | ++ 0 % + (0/13) + | +
+ + src/app/pages/home/home.component.ts + | ++ component + | ++ HomeComponent + | ++ 0 % + (0/8) + | +
+ + src/app/pages/library/library.component.ts + | ++ component + | ++ LibraryComponent + | ++ 0 % + (0/8) + | +
+ + src/app/pages/message-admin/message-admin.component.ts + | ++ component + | ++ MessageAdminComponent + | ++ 0 % + (0/5) + | +
+ + src/app/pages/pages.component.ts + | ++ component + | ++ PagesComponent + | ++ 0 % + (0/3) + | +
+ + src/app/pages/pages.component.ts + | ++ function + | ++ init_plugins + | ++ 0 % + (0/1) + | +
+ + src/app/pages/pages.routes.ts + | ++ variable + | ++ PAGES_ROUTES + | ++ 0 % + (0/1) + | +
+ + src/app/pages/profile/profile.component.ts + | ++ component + | ++ ProfileComponent + | ++ 0 % + (0/19) + | +
+ + src/app/pages/search/search.component.ts + | ++ component + | ++ SearchComponent + | ++ 0 % + (0/12) + | +
+ + src/app/pipes/thousands.pipe.ts + | ++ pipe + | ++ ThousandsPipe + | ++ 0 % + (0/1) + | +
+ + src/app/register/login.component.ts + | ++ component + | ++ LoginComponent + | ++ 0 % + (0/9) + | +
+ + src/app/register/login.component.ts + | ++ function + | ++ init_plugins + | ++ 0 % + (0/1) + | +
+ + src/app/register/register.component.ts + | ++ component + | ++ RegisterComponent + | ++ 0 % + (0/17) + | +
+ + src/app/register/register.component.ts + | ++ function + | ++ init_plugins + | ++ 0 % + (0/1) + | +
+ + src/app/services/database.service.ts + | ++ injectable + | ++ DatabaseService + | ++ 0 % + (0/10) + | +
+ + src/app/services/date.service.ts + | ++ injectable + | ++ DateService + | ++ 0 % + (0/5) + | +
+ + src/app/services/sidebar.service.ts + | ++ injectable + | ++ SidebarService + | ++ 0 % + (0/4) + | +
+ + src/app/shared/header/header.component.ts + | ++ component + | ++ HeaderComponent + | ++ 0 % + (0/8) + | +
+ + src/app/shared/messages/messages.component.ts + | ++ component + | ++ MessagesComponent + | ++ 0 % + (0/6) + | +
+ + src/app/shared/notifications/notifications.component.ts + | ++ component + | ++ NotificationsComponent + | ++ 0 % + (0/5) + | +
+ + src/app/shared/sidebar/sidebar.component.ts + | ++ component + | ++ SidebarComponent + | ++ 0 % + (0/8) + | +
+ + src/data/categories.data.ts + | ++ variable + | ++ CATEGORIES + | ++ 0 % + (0/1) + | +
+ + src/data/menuadmin.data.ts + | ++ variable + | ++ MENU_ADMIN + | ++ 0 % + (0/1) + | +
+ + src/environments/environment.prod.ts + | ++ variable + | ++ environment + | ++ 0 % + (0/1) + | +
+ + src/environments/environment.ts + | ++ variable + | ++ environment + | ++ 0 % + (0/1) + | +
+ + src/test.ts + | ++ variable + | ++ context + | ++ 0 % + (0/1) + | +
+ + src/test.ts + | ++ variable + | ++ require + | ++ 0 % + (0/1) + | +
+
+ src/app/services/guards/admin.guard.ts
+
+ Methods+ |
+
+
|
+
+constructor(router: Router)
+ |
+ ||||||
+ Defined in src/app/services/guards/admin.guard.ts:7
+ |
+ ||||||
+
+ Parameters :
+
+
|
+
+ + + + canActivate + + + + | +
+canActivate()
+ |
+
+ Defined in src/app/services/guards/admin.guard.ts:13
+ |
+
+
+
+ Returns :
+ boolean
+
+ |
+
import { Injectable } from '@angular/core';
+import { CanActivate, Router } from '@angular/router';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AdminGuard implements CanActivate {
+
+ constructor(private router:Router){
+
+ }
+
+ canActivate() {
+ const admin = JSON.parse(localStorage.getItem('user')).role;
+
+ if( admin === 'admin' ) {
+ return true;
+ }else {
+ console.error('Bloqueado por el AdminGuard');
+ this.router.navigate(['/forbidden']);
+ return false;
+ }
+ }
+}
+ +
+ src/app/services/guards/login-guard.guard.ts
+
+ Methods+ |
+
+
|
+
+constructor(router: Router)
+ |
+ ||||||
+ + | +||||||
+
+ Parameters :
+
+
|
+
+ + + + canActivate + + + + | +
+canActivate()
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
import { Injectable } from '@angular/core';
+import { CanActivate, Router } from '@angular/router';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class LoginGuardGuard implements CanActivate {
+
+ constructor(private router:Router){
+
+ }
+
+ canActivate() {
+ const session = JSON.parse(localStorage.getItem('session')).session;
+
+ if(session) {
+ return true;
+ }else {
+ console.error('Bloqueado por el Guard');
+ this.router.navigate(['/login']);
+ return false;
+ }
+ }
+}
+
+ +
+ src/app/services/database.service.ts
+
+ Properties+ |
+
+ + | +
+ Methods+ |
+
+
|
+
+constructor(afs: AngularFirestore)
+ |
+ ||||||
+ Defined in src/app/services/database.service.ts:13
+ |
+ ||||||
+
+ Parameters :
+
+
|
+
+ + + + Public + addData + + + + | +|||||||||
+
+ addData(collection: string, document: any)
+ |
+ |||||||||
+ Defined in src/app/services/database.service.ts:38
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any
+
+
+
+
+ |
+
+ + + + Public + addDataIdCustom + + + + | +||||||||||||
+
+ addDataIdCustom(collection: string, id: string, document: any)
+ |
+ ||||||||||||
+ Defined in src/app/services/database.service.ts:32
+ |
+ ||||||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any
+
+
+
+
+ |
+
+ + + + Public + deleteData + + + + | +|||||||||
+
+ deleteData(collection: string, id: string)
+ |
+ |||||||||
+ Defined in src/app/services/database.service.ts:50
+ |
+ |||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any
+
+
+
+
+ |
+
+ + + + Public + getData + + + + | +||||||
+
+ getData(collection: string)
+ |
+ ||||||
+ Defined in src/app/services/database.service.ts:20
+ |
+ ||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any
+
+
+
+
+ |
+
+ + + + Public + getDataQuery + + + + | +|||||||||||||||
+
+ getDataQuery(collection: string, query: string, operator: any, value: any)
+ |
+ |||||||||||||||
+ Defined in src/app/services/database.service.ts:26
+ |
+ |||||||||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any
+
+
+
+
+ |
+
+ + + + Public + updateData + + + + | +||||||||||||
+
+ updateData(collection: string, id: string, document: any)
+ |
+ ||||||||||||
+ Defined in src/app/services/database.service.ts:44
+ |
+ ||||||||||||
+
+
+ Parameters :
+
+
+
+
+ Returns :
+ any
+
+
+
+
+ |
+
+ + + + Public + afs + + + + | +
+ afs:
+ |
+
+ Type : AngularFirestore
+
+ |
+
+ Defined in src/app/services/database.service.ts:15
+ |
+
+ + + + books + + + + | +
+ books:
+ |
+
+ Type : any[]
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/services/database.service.ts:13
+ |
+
import { Injectable } from '@angular/core';
+import { Books } from "../interface/books.interface";
+
+// Angularfire2
+import { AngularFirestore } from 'angularfire2/firestore';
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DatabaseService {
+
+ books: any[] = [];
+
+ constructor( public afs: AngularFirestore ) {
+ }
+
+ // Retorna Observable
+ // Trae toda la data de una colección específica.
+ public getData( collection:string ){
+ return this.afs.collection<any>( collection );
+ }
+
+ // Retorna Observable
+ // Trae la data que se especifica en la query, de una colección específica.
+ public getDataQuery( collection:string, query:string, operator:any, value:any ){
+ return this.afs.collection<any>( collection, ref => ref.where(query, operator, value));
+ }
+
+ // Retorna Promesa
+ // Agrega data con identificador específico.
+ public addDataIdCustom( collection:string, id:string, document:any ){
+ return this.afs.collection<any>( collection ).doc( id ).set( document );
+ }
+
+ // Retorna Promesa
+ // Agrega data sin identificador específico
+ public addData( collection:string, document:any ){
+ return this.afs.collection<any>( collection ).add( document );
+ }
+
+ // Retorna Promesa
+ // Actualiza la data según el id y el documento a modificar
+ public updateData( collection:string, id:string, document:any ){
+ return this.afs.collection<any>( collection ).doc( id ).update( document );
+ }
+
+ // Retorna Promesa
+ // Borra la data según el id especificado
+ public deleteData( collection:string, id:string ){
+ return this.afs.collection<any>( collection ).doc( id ).delete();
+ }
+}
+ +
+ src/app/services/date.service.ts
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ Defined in src/app/services/date.service.ts:6
+ |
+
+ + + + Public + actual_date + + + + | +
+
+ actual_date()
+ |
+
+ Defined in src/app/services/date.service.ts:11
+ |
+
+
+
+ Returns :
+ string
+
+ |
+
+ + + + Public + actual_day + + + + | +
+
+ actual_day()
+ |
+
+ Defined in src/app/services/date.service.ts:29
+ |
+
+
+
+ Returns :
+ string
+
+ |
+
+ + + + Public + actual_hour + + + + | +
+
+ actual_hour()
+ |
+
+ Defined in src/app/services/date.service.ts:43
+ |
+
+
+
+ Returns :
+ string
+
+ |
+
import { Injectable } from '@angular/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DateService {
+
+ constructor() { }
+
+ // Extrae y retorna la fecha actual con un formato correcto
+ public actual_date():string{
+ let date = new Date();
+ let dd, mm, hh, m;
+ let day = date.getDate();
+ let month = (date.getMonth().valueOf() + 1);
+ let year = date.getFullYear();
+ let hour = date.getHours();
+ let min = date.getMinutes();
+
+ if( day < 10 ) { dd = '0'+day; } else{ dd = day; }
+ if( month < 10 ) { mm = '0'+month; } else{ mm = month; }
+ if( hour < 10 ){ hh = '0'+hour; } else{ hh = hour; }
+ if( min < 10 ) { m = '0'+min; } else{ m = min; }
+
+ return `${ mm }-${ dd }-${ year } ${hh}:${m}`;
+ }
+
+ // Extrae y retorna el día actual
+ public actual_day():string{
+ let date = new Date();
+ let dd, mm;
+ let day = date.getDate();
+ let month = (date.getMonth().valueOf() + 1);
+ let year = date.getFullYear();
+
+ if( day < 10 ) { dd = '0'+ day; } else{ dd = day; }
+ if( month < 10 ) { mm = '0'+ month; } else{ mm = month; }
+
+ return `${ mm }-${ dd }-${ year }`;
+ }
+
+ // Extrae y retorna la hora actual
+ public actual_hour():string{
+ let date = new Date();
+ let hh, m;
+ let hour = date.getHours();
+ let min = date.getMinutes();
+
+ if( hour < 10 ){ hh = '0'+hour; } else{ hh = hour; }
+ if( min < 10 ) { m = '0'+min; } else{ m = min; }
+
+ return `${hh}:${m}`;
+ }
+}
+ +
+ src/app/services/sidebar.service.ts
+
+ Properties+ |
+
+
|
+
+ Methods+ |
+
+
|
+
+constructor()
+ |
+
+ Defined in src/app/services/sidebar.service.ts:11
+ |
+
+ + + + defMenu + + + + | +
+defMenu()
+ |
+
+ Defined in src/app/services/sidebar.service.ts:18
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ + + + menu + + + + | +
+ menu:
+ |
+
+ Type : any
+
+ |
+
+ Default value : []
+ |
+
+ Defined in src/app/services/sidebar.service.ts:11
+ |
+
import { Injectable } from '@angular/core';
+
+import { MENU_ADMIN } from '../../data/menuadmin.data';
+import { CATEGORIES } from '../../data/categories.data';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SidebarService {
+
+ menu:any=[];
+
+ constructor() {
+ this.defMenu();
+ setInterval( () => { this.defMenu(); }, 5000);
+ }
+
+ defMenu(){
+ if (JSON.parse(localStorage.getItem("user")).role === 'admin'){
+ this.menu = MENU_ADMIN;
+ }else if (JSON.parse(localStorage.getItem("user")).role === 'normal'){
+ this.menu = CATEGORIES;
+ }
+ }
+}
+
+ +
+ src/app/interface/books.interface.ts
+
+ Properties+ |
+
+ + | +
+ + author + | +
+ author:
+ |
+
+ Type : string
+
+ |
+
+ + categories + | +
+ categories:
+ |
+
+ Type : Array<string>
+
+ |
+
+ + comment + | +
+ comment:
+ |
+
+ Type : string
+
+ |
+
+ + date + | +
+ date:
+ |
+
+ Type : any
+
+ |
+
+ + editorial + | +
+ editorial:
+ |
+
+ Type : string
+
+ |
+
+ + id + | +
+ id:
+ |
+
+ Type : string
+
+ |
+
+ + images + | +
+ images:
+ |
+
+ Type : Array<string>
+
+ |
+
+ Optional + | +
+ + language + | +
+ language:
+ |
+
+ Type : string
+
+ |
+
+ + num_page + | +
+ num_page:
+ |
+
+ Type : number
+
+ |
+
+ + original + | +
+ original:
+ |
+
+ Type : boolean
+
+ |
+
+ + price + | +
+ price:
+ |
+
+ Type : number
+
+ |
+
+ Optional + | +
+ + status + | +
+ status:
+ |
+
+ Type : string
+
+ |
+
+ Optional + | +
+ + title + | +
+ title:
+ |
+
+ Type : string
+
+ |
+
+ + transaction + | +
+ transaction:
+ |
+
+ Type : string
+
+ |
+
+ + type + | +
+ type:
+ |
+
+ Type : string
+
+ |
+
+ + uid + | +
+ uid:
+ |
+
+ Type : string
+
+ |
+
+ Optional + | +
+ + user + | +
+ user:
+ |
+
+ Type : any
+
+ |
+
import { Message } from '@angular/compiler/src/i18n/i18n_ast';
+// Interface libro
+export interface Books{
+ author: string;
+ title: string;
+ editorial: string;
+ type: string;
+ categories: Array<string>;
+ language: string;
+ comment: string;
+ num_page: number;
+ original: boolean;
+ transaction: string;
+ user: any;
+ date: any;
+ id: string;
+ uid?: string;
+ price?: number;
+ images?: Array<string>;
+ status?: string;
+};
+
+// Interface users
+export interface Users{
+ uid: string;
+ name: string;
+ rut: string;
+ last_name1: string;
+ last_name2: string;
+ email: string;
+ categories: Array<string>;
+ google: boolean;
+ status: boolean;
+ role: string;
+ created_date: any;
+ firtSession: boolean;
+ img?: string;
+ preferences?: Array<string>;
+ phone?: string;
+};
+
+// Interface del mensaje para establecer la transacción
+export interface Message{
+ transaction: string;
+ pref: any;
+ text: Array<any>;
+ date: any;
+ book: any;
+ user_owner: any;
+ uid_interested: Users;
+ status: boolean;
+ price?: number;
+};
+
+// Interface de los reportes de imagenes y de usuario
+export interface Report{
+ id: string;
+ user: any;
+ day: string;
+ hour: string;
+ type: string;
+ status: string;
+ img?: any;
+ user_reported?: any;
+};
+ +
+ src/app/interface/books.interface.ts
+
+ Properties+ |
+
+
|
+
+ + book + | +
+ book:
+ |
+
+ Type : any
+
+ |
+
+ + date + | +
+ date:
+ |
+
+ Type : any
+
+ |
+
+ + pref + | +
+ pref:
+ |
+
+ Type : any
+
+ |
+
+ + price + | +
+ price:
+ |
+
+ Type : number
+
+ |
+
+ Optional + | +
+ + status + | +
+ status:
+ |
+
+ Type : boolean
+
+ |
+
+ + text + | +
+ text:
+ |
+
+ Type : Array<any>
+
+ |
+
+ + transaction + | +
+ transaction:
+ |
+
+ Type : string
+
+ |
+
+ + uid_interested + | +
+ uid_interested:
+ |
+
+ Type : Users
+
+ |
+
+ + user_owner + | +
+ user_owner:
+ |
+
+ Type : any
+
+ |
+
import { Message } from '@angular/compiler/src/i18n/i18n_ast';
+// Interface libro
+export interface Books{
+ author: string;
+ title: string;
+ editorial: string;
+ type: string;
+ categories: Array<string>;
+ language: string;
+ comment: string;
+ num_page: number;
+ original: boolean;
+ transaction: string;
+ user: any;
+ date: any;
+ id: string;
+ uid?: string;
+ price?: number;
+ images?: Array<string>;
+ status?: string;
+};
+
+// Interface users
+export interface Users{
+ uid: string;
+ name: string;
+ rut: string;
+ last_name1: string;
+ last_name2: string;
+ email: string;
+ categories: Array<string>;
+ google: boolean;
+ status: boolean;
+ role: string;
+ created_date: any;
+ firtSession: boolean;
+ img?: string;
+ preferences?: Array<string>;
+ phone?: string;
+};
+
+// Interface del mensaje para establecer la transacción
+export interface Message{
+ transaction: string;
+ pref: any;
+ text: Array<any>;
+ date: any;
+ book: any;
+ user_owner: any;
+ uid_interested: Users;
+ status: boolean;
+ price?: number;
+};
+
+// Interface de los reportes de imagenes y de usuario
+export interface Report{
+ id: string;
+ user: any;
+ day: string;
+ hour: string;
+ type: string;
+ status: string;
+ img?: any;
+ user_reported?: any;
+};
+ +
+ src/app/interface/books.interface.ts
+
+ Properties+ |
+
+ + | +
+ + day + | +
+ day:
+ |
+
+ Type : string
+
+ |
+
+ + hour + | +
+ hour:
+ |
+
+ Type : string
+
+ |
+
+ + id + | +
+ id:
+ |
+
+ Type : string
+
+ |
+
+ + img + | +
+ img:
+ |
+
+ Type : any
+
+ |
+
+ Optional + | +
+ + status + | +
+ status:
+ |
+
+ Type : string
+
+ |
+
+ + type + | +
+ type:
+ |
+
+ Type : string
+
+ |
+
+ + user + | +
+ user:
+ |
+
+ Type : any
+
+ |
+
+ + user_reported + | +
+ user_reported:
+ |
+
+ Type : any
+
+ |
+
+ Optional + | +
import { Message } from '@angular/compiler/src/i18n/i18n_ast';
+// Interface libro
+export interface Books{
+ author: string;
+ title: string;
+ editorial: string;
+ type: string;
+ categories: Array<string>;
+ language: string;
+ comment: string;
+ num_page: number;
+ original: boolean;
+ transaction: string;
+ user: any;
+ date: any;
+ id: string;
+ uid?: string;
+ price?: number;
+ images?: Array<string>;
+ status?: string;
+};
+
+// Interface users
+export interface Users{
+ uid: string;
+ name: string;
+ rut: string;
+ last_name1: string;
+ last_name2: string;
+ email: string;
+ categories: Array<string>;
+ google: boolean;
+ status: boolean;
+ role: string;
+ created_date: any;
+ firtSession: boolean;
+ img?: string;
+ preferences?: Array<string>;
+ phone?: string;
+};
+
+// Interface del mensaje para establecer la transacción
+export interface Message{
+ transaction: string;
+ pref: any;
+ text: Array<any>;
+ date: any;
+ book: any;
+ user_owner: any;
+ uid_interested: Users;
+ status: boolean;
+ price?: number;
+};
+
+// Interface de los reportes de imagenes y de usuario
+export interface Report{
+ id: string;
+ user: any;
+ day: string;
+ hour: string;
+ type: string;
+ status: string;
+ img?: any;
+ user_reported?: any;
+};
+ +
+ src/app/interface/books.interface.ts
+
+ Properties+ |
+
+
|
+
+ + categories + | +
+ categories:
+ |
+
+ Type : Array<string>
+
+ |
+
+ + created_date + | +
+ created_date:
+ |
+
+ Type : any
+
+ |
+
+ + email + | +
+ email:
+ |
+
+ Type : string
+
+ |
+
+ + firtSession + | +
+ firtSession:
+ |
+
+ Type : boolean
+
+ |
+
+ + google + | +
+ google:
+ |
+
+ Type : boolean
+
+ |
+
+ + img + | +
+ img:
+ |
+
+ Type : string
+
+ |
+
+ Optional + | +
+ + last_name1 + | +
+ last_name1:
+ |
+
+ Type : string
+
+ |
+
+ + last_name2 + | +
+ last_name2:
+ |
+
+ Type : string
+
+ |
+
+ + name + | +
+ name:
+ |
+
+ Type : string
+
+ |
+
+ + phone + | +
+ phone:
+ |
+
+ Type : string
+
+ |
+
+ Optional + | +
+ + preferences + | +
+ preferences:
+ |
+
+ Type : Array<string>
+
+ |
+
+ Optional + | +
+ + role + | +
+ role:
+ |
+
+ Type : string
+
+ |
+
+ + rut + | +
+ rut:
+ |
+
+ Type : string
+
+ |
+
+ + status + | +
+ status:
+ |
+
+ Type : boolean
+
+ |
+
+ + uid + | +
+ uid:
+ |
+
+ Type : string
+
+ |
+
import { Message } from '@angular/compiler/src/i18n/i18n_ast';
+// Interface libro
+export interface Books{
+ author: string;
+ title: string;
+ editorial: string;
+ type: string;
+ categories: Array<string>;
+ language: string;
+ comment: string;
+ num_page: number;
+ original: boolean;
+ transaction: string;
+ user: any;
+ date: any;
+ id: string;
+ uid?: string;
+ price?: number;
+ images?: Array<string>;
+ status?: string;
+};
+
+// Interface users
+export interface Users{
+ uid: string;
+ name: string;
+ rut: string;
+ last_name1: string;
+ last_name2: string;
+ email: string;
+ categories: Array<string>;
+ google: boolean;
+ status: boolean;
+ role: string;
+ created_date: any;
+ firtSession: boolean;
+ img?: string;
+ preferences?: Array<string>;
+ phone?: string;
+};
+
+// Interface del mensaje para establecer la transacción
+export interface Message{
+ transaction: string;
+ pref: any;
+ text: Array<any>;
+ date: any;
+ book: any;
+ user_owner: any;
+ uid_interested: Users;
+ status: boolean;
+ price?: number;
+};
+
+// Interface de los reportes de imagenes y de usuario
+export interface Report{
+ id: string;
+ user: any;
+ day: string;
+ hour: string;
+ type: string;
+ status: string;
+ img?: any;
+ user_reported?: any;
+};
+