diff --git a/src/app/shared/data/rest/the-movie-db/the-movie-db.constant.ts b/src/app/shared/data/rest/the-movie-db/the-movie-db.constant.ts index 4f87984..9b6f143 100644 --- a/src/app/shared/data/rest/the-movie-db/the-movie-db.constant.ts +++ b/src/app/shared/data/rest/the-movie-db/the-movie-db.constant.ts @@ -3,6 +3,8 @@ import { environment } from 'src/environments/environment.development'; const tmdbApiBaseUrl = 'https://api.themoviedb.org/3/'; // TODO: Move this to the header -const apiKeyQueryParam = `?api_key=${environment.API_KEY}`; +export const apiKeyQueryParam = `?api_key=${environment.API_KEY}`; export const tmdbApiSearchQuery = `${tmdbApiBaseUrl}search/movie${apiKeyQueryParam}&query=`; + +export const tmdbApiFindById = `${tmdbApiBaseUrl}movie/`; diff --git a/src/app/shared/data/rest/the-movie-db/the-movie-db.service.ts b/src/app/shared/data/rest/the-movie-db/the-movie-db.service.ts index 399dae1..1155e4a 100644 --- a/src/app/shared/data/rest/the-movie-db/the-movie-db.service.ts +++ b/src/app/shared/data/rest/the-movie-db/the-movie-db.service.ts @@ -1,8 +1,12 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, tap } from 'rxjs'; -import { tmdbApiSearchQuery } from './the-movie-db.constant'; -import { TmdbSearchResponse } from './the-movie-db.model'; +import { + apiKeyQueryParam, + tmdbApiFindById, + tmdbApiSearchQuery, +} from './the-movie-db.constant'; +import { TmdbMovie, TmdbSearchResponse } from './the-movie-db.model'; @Injectable({ providedIn: 'root', @@ -15,4 +19,10 @@ export class TheMovieDbService { `${tmdbApiSearchQuery}${query}` ); } + + public searchMovieById(movieId: number): Observable { + return this.httpClient.get( + `${tmdbApiFindById}${movieId}${apiKeyQueryParam}` + ); + } } diff --git a/src/app/shared/data/store/movie-store/movie-store.service.ts b/src/app/shared/data/store/movie-store/movie-store.service.ts index 18315a0..103e6aa 100644 --- a/src/app/shared/data/store/movie-store/movie-store.service.ts +++ b/src/app/shared/data/store/movie-store/movie-store.service.ts @@ -1,6 +1,14 @@ import { Injectable } from '@angular/core'; import { TheMovieDbService } from '../../rest/the-movie-db/the-movie-db.service'; -import { ReplaySubject } from 'rxjs'; +import { + BehaviorSubject, + Observable, + ReplaySubject, + filter, + map, + of, + switchMap, +} from 'rxjs'; import { TmdbMovie, TmdbSearchResponse, @@ -10,16 +18,38 @@ import { providedIn: 'root', }) export class MovieStoreService { - private _movies = new ReplaySubject(1); // TODO: Update to custom Movie type: - public movies$ = this._movies.asObservable(); + private _tmdbSearchResponse$ = new BehaviorSubject( + null // null needed to check if the response has been initialised + ); // TODO: Update to custom Movie type: + public tmdbSearchResponse$ = this._tmdbSearchResponse$ + .asObservable() + .pipe(filter((response) => !!response)); // filter out null public constructor(private theMovieDbService: TheMovieDbService) {} + public getMovieDetail(movieId: number): Observable { + return this._tmdbSearchResponse$.pipe( + switchMap( + (response) => + response && response.results.length > 0 + ? of(response).pipe( + map( + ({ results }) => + results.find(({ id }) => id === movieId) as TmdbMovie + ) + ) + : this.theMovieDbService.searchMovieById(movieId) // lookup if not in store, this allows direct loading of detail page + ) + ); + } + public searchMovies(searchQuery: string, page = 1): void { searchQuery = `${searchQuery}&page=${page}`; this.theMovieDbService .searchMovies(searchQuery) - .subscribe((tmdbMovieResponse) => this._movies.next(tmdbMovieResponse)); + .subscribe((tmdbMovieResponse) => + this._tmdbSearchResponse$.next(tmdbMovieResponse) + ); } } diff --git a/src/app/views/movie-detail/movie-detail.component.html b/src/app/views/movie-detail/movie-detail.component.html index 537d394..7dc9606 100644 --- a/src/app/views/movie-detail/movie-detail.component.html +++ b/src/app/views/movie-detail/movie-detail.component.html @@ -1 +1,5 @@ -

movie-detail works!

+ +@if(tmdbMovie$ | async; as tmdbMovie){ +

{{ tmdbMovie.title }}

+ +} @else { 🍿 Movie not found 😔 } diff --git a/src/app/views/movie-detail/movie-detail.component.ts b/src/app/views/movie-detail/movie-detail.component.ts index 9ce3c7e..d5295e7 100644 --- a/src/app/views/movie-detail/movie-detail.component.ts +++ b/src/app/views/movie-detail/movie-detail.component.ts @@ -1,5 +1,9 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { MovieStoreService } from 'src/app/shared/data/store/movie-store/movie-store.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Observable, switchMap } from 'rxjs'; +import { TmdbMovie } from 'src/app/shared/data/rest/the-movie-db/the-movie-db.model'; @Component({ selector: 'mose-movie-detail', @@ -9,4 +13,29 @@ import { CommonModule } from '@angular/common'; styleUrl: './movie-detail.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MovieDetailComponent {} +export class MovieDetailComponent { + public movieId: number | undefined; + // public tmdbMovie$: Observable; + + public tmdbMovie$ = this.route.paramMap.pipe( + switchMap((params) => { + const movieId = Number(params.get('movieId')); + return this.movieStoreService.getMovieDetail(movieId); + }) + ); + + public constructor( + public movieStoreService: MovieStoreService, + private route: ActivatedRoute + ) { + // public route: Route + // this.movieId = this.route.snapshot.paramMap.get('movieId') !== null; + // this.tmdbMovie$ = this.route.paramMap.pipe( + // switchMap((params) => { + // this.movieId = Number(params.get('movieId')); + // return this.movieStoreService.getMovieDetail(this.movieId); + // }) + // ); + // console.log(this.movieId); + } +} diff --git a/src/app/views/search/search.component.html b/src/app/views/search/search.component.html index d31ee2b..aabd429 100644 --- a/src/app/views/search/search.component.html +++ b/src/app/views/search/search.component.html @@ -15,7 +15,7 @@
- @if (movieStoreService.movies$ | async; as moviesResponse) { + @if (movieStoreService.tmdbSearchResponse$ | async; as moviesResponse) { {{ moviesResponse?.total_results }} total results
diff --git a/src/app/views/search/search.component.ts b/src/app/views/search/search.component.ts index 0c807f5..41a87ea 100644 --- a/src/app/views/search/search.component.ts +++ b/src/app/views/search/search.component.ts @@ -7,6 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { debounce, debounceTime } from 'rxjs'; +import { Router } from '@angular/router'; @Component({ selector: 'mose-search', @@ -30,7 +31,10 @@ export class SearchComponent { // TODO: Move this to the MovieStoreService: private searchQuery: string | undefined; - public constructor(public movieStoreService: MovieStoreService) { + public constructor( + public movieStoreService: MovieStoreService, + public router: Router + ) { this.searchFormControl.valueChanges .pipe(debounceTime(500)) .subscribe((searchQuery) => { @@ -50,5 +54,6 @@ export class SearchComponent { public goToMovieDetail(movieId: number): void { console.log({ movieId }); + this.router.navigate([`/movie-detail`, { movieId }]); } }