Pagina nueva

This commit is contained in:
Daniel Cortes
2020-05-29 16:56:12 -04:00
parent 1985848922
commit ca1157978c
14 changed files with 247 additions and 75 deletions

View File

@@ -1,10 +1,12 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { Routes, RouterModule } from '@angular/router';
import {HomepageComponent} from "./homepage/homepage.component"; import {HomepageComponent} from "./homepage/homepage.component";
import {SearchComponent} from "./search/search.component";
const routes: Routes = [ const routes: Routes = [
{path: '', component: HomepageComponent} {path: '', component: HomepageComponent},
{path: 'search', component: SearchComponent}
]; ];
@NgModule({ @NgModule({

View File

@@ -3,17 +3,19 @@ import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { SearchHomeComponent } from './homepage/searchHome/searchHome.component'; import { SearchBarComponent } from './homepage/searchBar/searchBar.component';
import {HttpClientModule} from "@angular/common/http"; import {HttpClientModule} from "@angular/common/http";
import { HomepageComponent } from './homepage/homepage.component'; import { HomepageComponent } from './homepage/homepage.component';
import { NavComponent } from './nav/nav.component'; import { NavComponent } from './nav/nav.component';
import { SearchComponent } from './search/search.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
SearchHomeComponent, SearchBarComponent,
HomepageComponent, HomepageComponent,
NavComponent, NavComponent,
SearchComponent,
], ],
imports: [ imports: [
HttpClientModule, HttpClientModule,

View File

@@ -3,7 +3,7 @@
<div class="hero-body"> <div class="hero-body">
<div class="container"> <div class="container">
<h1 class="title">Busca la musica que disfrutas!</h1> <h1 class="title">Busca la musica que disfrutas!</h1>
<app-search></app-search> <app-search-bar></app-search-bar>
</div> </div>
</div> </div>
</section> </section>

View File

@@ -1,9 +1,9 @@
<div class="field has-addons"> <div class="field has-addons">
<div class="control is-expanded"> <div class="control is-expanded">
<input #input class="input" type="search" (focus)="showList = true" (input)="searchTerm$.next(input.value)"> <input #input class="input" type="search" (focus)="showList = true" [value]="query$.getValue()" (input)="query$.next(input.value)" (keyup.enter)="search()">
</div> </div>
<div class="control"> <div class="control">
<a class="button is-white"><span class="icon"><i class="fas fa-search"></i></span></a> <a class="button" [class]="button_color"><span class="icon"><i class="fas fa-search"></i></span></a>
</div> </div>
</div> </div>
@@ -22,8 +22,10 @@
</div> </div>
<div *ngFor="let result of discs" class="media disc"> <div *ngFor="let result of discs" class="media disc">
<figure class="media-left"> <figure class="media-left">
<img *ngIf="result.cover_art" class="image is-64x64 cropped" src="{{result.cover_art.small}}" alt="{{result.title}} cover art"> <img *ngIf="result.cover_art" class="image is-64x64 cropped" src="{{result.cover_art.small}}"
<img *ngIf="!result.cover_art" class="image is-64x64 cropped" src="../../../assets/svg/placeholder.svg" alt="{{result.title}} missing cover art"> alt="{{result.title}} cover art">
<img *ngIf="!result.cover_art" class="image is-64x64 cropped" src="../../../assets/svg/placeholder.svg"
alt="{{result.title}} missing cover art">
</figure> </figure>
<div class="media-content"> <div class="media-content">
<p>{{result.title}}</p> <p>{{result.title}}</p>

View File

@@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchHomeComponent } from './searchHome.component'; import { SearchBarComponent } from './searchBar.component';
describe('SearchComponent', () => { describe('SearchComponent', () => {
let component: SearchHomeComponent; let component: SearchBarComponent;
let fixture: ComponentFixture<SearchHomeComponent>; let fixture: ComponentFixture<SearchBarComponent>;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SearchHomeComponent ] declarations: [ SearchBarComponent ]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(SearchHomeComponent); fixture = TestBed.createComponent(SearchBarComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -0,0 +1,66 @@
import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core';
import {BehaviorSubject, forkJoin, Subject} from "rxjs";
import {SearchService} from "../../services/search.service";
import {Artist, Disc, Recording} from "../../models/brainz";
import {Router} from "@angular/router";
@Component({
selector: 'app-search-bar',
templateUrl: './searchBar.component.html',
styleUrls: ['./searchBar.component.scss']
})
export class SearchBarComponent implements OnInit {
@ViewChild("input") input: ElementRef;
showList: boolean;
artists: Artist[] = [];
discs: Disc[] = [];
recordings: Recording[] = [];
@Input() query$ = new BehaviorSubject<string>("");
@Input() button_color = "is-white";
@Input() autocomplete = true;
constructor(private searchService: SearchService, private router: Router) {
}
areResults() {
return this.artists.length > 0 || this.discs.length > 0 || this.recordings.length > 0;
}
show() {
if (this.input.nativeElement === document.activeElement) return true;
this.showList = false;
}
ngOnInit(): void {
this.query$.subscribe(() => {
this.artists = [];
this.discs = [];
this.recordings = [];
}
);
let searchArtist = this.searchService.searchArtist(this.query$).subscribe((result) => {
this.artists = result.artists;
});
let searchDisc = this.searchService.searchDisc(this.query$).subscribe((result) => {
this.discs = result.discs;
});
let searchRecording = this.searchService.searchRecording(this.query$).subscribe((result) => {
this.recordings = result.recordings;
});
}
search() {
this.router.navigate(['search'], {
state: {
artists: this.artists,
discs: this.discs,
recordings: this.recordings
},
queryParams: {query: this.query$.getValue()}
});
}
}

View File

@@ -1,51 +0,0 @@
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {BehaviorSubject, forkJoin, Subject} from "rxjs";
import {SearchService} from "../../search.service";
import {Artist, Disc, Recording} from "../../models/brainz";
@Component({
selector: 'app-search',
templateUrl: './searchHome.component.html',
styleUrls: ['./searchHome.component.scss']
})
export class SearchHomeComponent implements OnInit {
@ViewChild("input") input: ElementRef;
showList: boolean;
artists: Artist[] = [];
discs: Disc[] = [];
recordings: Recording[] = [];
searchTerm$ = new Subject<string>();
constructor(private searchService: SearchService) {
}
areResults() {
return this.artists.length > 0 || this.discs.length > 0 || this.recordings.length > 0;
}
show() {
if (this.input.nativeElement === document.activeElement) return true;
this.showList = false;
}
ngOnInit(): void {
this.searchTerm$.subscribe(() => {
this.artists = [];
this.discs = [];
this.recordings = [];
}
);
let searchArtist = this.searchService.searchArtist(this.searchTerm$).subscribe((result) => {
this.artists = result.artists;
});
let searchDisc = this.searchService.searchDisc(this.searchTerm$).subscribe((result) => {
this.discs = result.discs;
});
let searchRecording = this.searchService.searchRecording(this.searchTerm$).subscribe((result) => {
this.recordings = result.recordings;
});
}
}

View File

@@ -0,0 +1,60 @@
<app-nav></app-nav>
<section class="hero">
<div class="hero-body">
<div class="container">
<app-search-bar [query$]="query$" [autocomplete]="false" [button_color]="'is-primary'"></app-search-bar>
</div>
</div>
</section>
<div class="container tabs is-boxed">
<ul>
<li [class.is-active]="artists_active" (click)="show_artist()">
<a>
<span class="icon is-small"><i class="fas fa-user" aria-hidden="true"></i></span>
<span>Artistas</span>
</a>
</li>
<li [class.is-active]="discs_active" (click)="show_discs()">
<a>
<span class="icon is-small"><i class="fas fa-compact-disc" aria-hidden="true"></i></span>
<span>Discos</span>
</a>
</li>
<li [class.is-active]="songs_active" (click)="show_songs()">
<a>
<span class="icon is-small"><i class="fas fa-music" aria-hidden="true"></i></span>
<span>Canciones</span>
</a>
</li>
</ul>
</div>
<ng-template [ngIf]="artists_active">
<div class="container">
<div class="media" *ngFor="let artist of artists">
<div class="media-content">
<p>{{artist.name}}</p>
</div>
</div>
</div>
</ng-template>
<ng-template [ngIf]="discs_active">
<div class="container">
<div class="media" *ngFor="let disc of discs">
<div class="media-content">
<p>{{disc.title}}</p>
</div>
</div>
</div>
</ng-template>
<ng-template [ngIf]="songs_active">
<div class="container">
<div class="media" *ngFor="let song of recordings">
<div class="media-content">
<p>{{song.title}}</p>
</div>
</div>
</div>
</ng-template>

View File

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchComponent } from './search.component';
describe('SearchComponent', () => {
let component: SearchComponent;
let fixture: ComponentFixture<SearchComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SearchComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SearchComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,66 @@
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {SearchService} from "../services/search.service";
import {map} from "rxjs/operators";
import {Artist, Disc, Recording} from "../models/brainz";
import {BehaviorSubject, Observable} from "rxjs";
@Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
query$ = new BehaviorSubject<string>("");
artists: Artist[] = [];
discs: Disc[] = [];
recordings: Recording[] = [];
artists_active = true;
discs_active = false;
songs_active= false;
constructor(private route: ActivatedRoute, private searchService: SearchService) {
this.route.queryParams.pipe(map(params => params['query'] as string)).subscribe((query) => {
this.query$.next(query);
});
}
ngOnInit(): void {
this.query$.subscribe(() => {
this.artists = [];
this.discs = [];
this.recordings = [];
});
this.searchService.searchArtist(this.query$).subscribe((result) => this.artists = result.artists);
this.searchService.searchDisc(this.query$).subscribe((result) => this.discs = result.discs);
this.searchService.searchRecording(this.query$).subscribe((result) => this.recordings = result.recordings);
}
show_artist() {
if(this.artists_active) return;
this.artists_active = true;
this.discs_active = false;
this.songs_active = false;
}
show_discs() {
if(this.discs_active) return;
this.artists_active = false;
this.discs_active = true;
this.songs_active = false;
}
show_songs() {
if(this.songs_active) return;
this.artists_active = false;
this.discs_active = false;
this.songs_active = true;
}
}

View File

@@ -2,7 +2,7 @@ import {Injectable} from '@angular/core';
import {forkJoin, merge, Observable, of} from "rxjs"; import {forkJoin, merge, Observable, of} from "rxjs";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {debounceTime, distinctUntilChanged, switchMap, tap} from "rxjs/operators"; import {debounceTime, distinctUntilChanged, switchMap, tap} from "rxjs/operators";
import {ArtistSearch, DiscSearch, RecordingSearch} from "./models/brainz"; import {ArtistSearch, DiscSearch, RecordingSearch} from "../models/brainz";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -13,39 +13,39 @@ export class SearchService {
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
} }
searchArtist(terms: Observable<string>): Observable<ArtistSearch> { searchArtist(terms: Observable<string>, page: number = 1): Observable<ArtistSearch> {
return terms.pipe( return terms.pipe(
debounceTime(400), debounceTime(400),
distinctUntilChanged(), distinctUntilChanged(),
switchMap(term => this.searchArtistQuery(term)) switchMap(term => this.searchArtistQuery(term, page))
); );
} }
searchDisc(terms: Observable<string>): Observable<DiscSearch> { searchDisc(terms: Observable<string>, page: number = 1): Observable<DiscSearch> {
return terms.pipe( return terms.pipe(
debounceTime(400), debounceTime(400),
distinctUntilChanged(), distinctUntilChanged(),
switchMap(term => this.searchDiscQuery(term)) switchMap(term => this.searchDiscQuery(term, page))
); );
} }
searchRecording(terms: Observable<string>): Observable<RecordingSearch> { searchRecording(terms: Observable<string>, page: number = 1): Observable<RecordingSearch> {
return terms.pipe( return terms.pipe(
debounceTime(400), debounceTime(400),
distinctUntilChanged(), distinctUntilChanged(),
switchMap(term => this.searchRecordingQuery(term)) switchMap(term => this.searchRecordingQuery(term, page))
); );
} }
private searchArtistQuery(term: string): Observable<ArtistSearch> { private searchArtistQuery(term: string, page: number): Observable<ArtistSearch> {
if (!term) { if (!term) {
return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, artists: []} as ArtistSearch); return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, artists: []} as ArtistSearch);
} }
return this.http.get<ArtistSearch>(`${this.baseUrl}/artist?query=${term}`); return this.http.get<ArtistSearch>(`${this.baseUrl}/artist?query=${term}&page=${page}`);
} }
private searchDiscQuery(term: string): Observable<DiscSearch> { private searchDiscQuery(term: string, page: number): Observable<DiscSearch> {
if (!term) { if (!term) {
return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, discs: []} as DiscSearch); return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, discs: []} as DiscSearch);
} }
@@ -53,7 +53,7 @@ export class SearchService {
return this.http.get<DiscSearch>(`${this.baseUrl}/disc?query=${term}`); return this.http.get<DiscSearch>(`${this.baseUrl}/disc?query=${term}`);
} }
private searchRecordingQuery(term: string): Observable<RecordingSearch> { private searchRecordingQuery(term: string, page: number): Observable<RecordingSearch> {
if (!term) { if (!term) {
return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, recordings: []} as RecordingSearch); return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, recordings: []} as RecordingSearch);
} }