Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mews Assignment #1

Open
wants to merge 56 commits into
base: initial-commit
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
088f199
Init NX standalone NG app
RonanCodes May 3, 2024
db7e66d
move all files to root level
RonanCodes May 3, 2024
a7b63c9
Tidy up readme
RonanCodes May 3, 2024
7bd6130
Tidy up readme
RonanCodes May 3, 2024
4224ec7
Update prefix from app to mose
RonanCodes May 3, 2024
abd28c4
Add initial requirements
RonanCodes May 3, 2024
a9561c5
Remove default component
RonanCodes May 3, 2024
22d790b
Save defaults for new component
RonanCodes May 3, 2024
3a95de0
Generate basic components and services
RonanCodes May 3, 2024
bcb863a
Add new routes, new favicon, and Angular Material
RonanCodes May 3, 2024
a9d21b9
Set a dark theme as default
RonanCodes May 3, 2024
cf7b7e2
prettier run all
RonanCodes May 3, 2024
b3ce4b8
Update readme
RonanCodes May 3, 2024
ce7edfa
Add a lint command for quick local checking
RonanCodes May 3, 2024
89ba667
Enable dark mode
RonanCodes May 3, 2024
64c0385
Get all quality checks passing
RonanCodes May 3, 2024
9416494
Add in some comments for global vars
RonanCodes May 3, 2024
71333e3
Remove TestBed as it's not needed for services and slows down the tes…
RonanCodes May 3, 2024
dd69a43
Add API key
RonanCodes May 3, 2024
063d9f8
tidy and add in the httpclient
RonanCodes May 3, 2024
e1a1414
Update default CI with deployment to GH pages
RonanCodes May 3, 2024
b0014d8
Fix nx format
RonanCodes May 3, 2024
b5059d5
fix test
RonanCodes May 3, 2024
82f41ef
Update ci
RonanCodes May 3, 2024
d5ccf05
Update routing and dist location
RonanCodes May 3, 2024
862aec0
Update location of DIST
RonanCodes May 3, 2024
72f1a47
Try a different action
RonanCodes May 3, 2024
2473e73
Updates
RonanCodes May 3, 2024
b58e3b8
Update base href
RonanCodes May 3, 2024
06dafc9
Tidy up
RonanCodes May 3, 2024
b034e9e
Tweaks
RonanCodes May 3, 2024
ec82cd2
use special ci cache
RonanCodes May 3, 2024
79bd294
revert
RonanCodes May 3, 2024
d37ad23
Downgrade nx to 17 to test GH page deployment
RonanCodes May 5, 2024
39f44c2
Revert "Downgrade nx to 17 to test GH page deployment"
RonanCodes May 5, 2024
6bdeb19
Test out artifact creation and version bump
RonanCodes May 5, 2024
ce39c93
Add TODO and comment out auto version and artefact upload
RonanCodes May 5, 2024
aab295e
Use separate services for the api integration and the store, loading …
RonanCodes May 7, 2024
c2ab711
Update styling
RonanCodes May 7, 2024
25572ad
Disable pagination if first or last page
RonanCodes May 7, 2024
96890f1
Increase font size
RonanCodes May 7, 2024
1d0e800
Add in pagination
RonanCodes May 7, 2024
0294e41
POC for table
RonanCodes May 7, 2024
18bcbeb
Enable loading of detail page directly from app start
RonanCodes May 7, 2024
7ad19dd
Add css grid to detail page
RonanCodes May 7, 2024
291dd78
Tidy up
RonanCodes May 7, 2024
cc931c4
Get all tests passing
RonanCodes May 7, 2024
d584214
Update linting
RonanCodes May 7, 2024
90545c8
Fix e2e lint
RonanCodes May 7, 2024
7129b08
Always get detail
RonanCodes May 7, 2024
294e270
Cache searchQuery to allow pagination when you go back to the search …
RonanCodes May 7, 2024
bad7da4
Update tests and tidy up
RonanCodes May 7, 2024
87dca9c
Update readme with images
RonanCodes May 7, 2024
3539d10
Update readme
RonanCodes May 7, 2024
bdf54d1
Update readme
RonanCodes May 7, 2024
987b91e
Add feedback comments
RonanCodes May 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use separate services for the api integration and the store, loading …
…the results with a debounce, and added in a button that allows you to go back to the search page from the movie detail page
RonanCodes committed May 7, 2024
commit aab295e87e7810b318be921a45c468a285b682fd
12 changes: 11 additions & 1 deletion src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { ApplicationConfig } from '@angular/core';
import { APP_INITIALIZER, ApplicationConfig } from '@angular/core';
import { provideRouter, withHashLocation } from '@angular/router';
import { appRoutes } from './app.routes';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { MovieStoreService } from './shared/data/store/movie-store/movie-store.service';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
providers: [
provideRouter(appRoutes, withHashLocation()),
provideAnimationsAsync(),
provideHttpClient(),
// {
// provide: APP_INITIALIZER,
// useFactory: (movieStoreService: MovieStoreService) => {
// movieStoreService.initStore();
// },
// deps: [MovieStoreService],
// },
],
};
16 changes: 0 additions & 16 deletions src/app/shared/data/rest/the-movie-db.service.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,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 tmdbApiSearchQuery = `${tmdbApiBaseUrl}search/movie${apiKeyQueryParam}&query=`;
23 changes: 23 additions & 0 deletions src/app/shared/data/rest/the-movie-db/the-movie-db.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export interface TmdbMovie {
adult: boolean;
backdrop_path: string | null;
genre_ids: number[];
id: number;
original_language: string;
original_title: string;
overview: string;
popularity: number;
poster_path: string | null;
release_date: string;
title: string;
video: boolean;
vote_average: number;
vote_count: number;
}

export interface TmdbSearchResponse {
page: number;
results: TmdbMovie[];
total_pages: number;
total_results: number;
}
18 changes: 18 additions & 0 deletions src/app/shared/data/rest/the-movie-db/the-movie-db.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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';

@Injectable({
providedIn: 'root',
})
export class TheMovieDbService {
public constructor(private httpClient: HttpClient) {}

public searchMovies(query: string): Observable<TmdbSearchResponse> {
return this.httpClient.get<TmdbSearchResponse>(
`${tmdbApiSearchQuery}${query}`
);
}
}
6 changes: 0 additions & 6 deletions src/app/shared/data/store/movie-store.service.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/app/shared/data/store/movie-store/movie-store.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
import { TheMovieDbService } from '../../rest/the-movie-db/the-movie-db.service';
import { ReplaySubject } from 'rxjs';
import {
TmdbMovie,
TmdbSearchResponse,
} from '../../rest/the-movie-db/the-movie-db.model';

@Injectable({
providedIn: 'root',
})
export class MovieStoreService {
private _movies = new ReplaySubject<TmdbSearchResponse>(1); // TODO: Update to custom Movie type:
public movies$ = this._movies.asObservable();

public constructor(private theMovieDbService: TheMovieDbService) {}

public searchMovies(searchQuery: string): void {
this.theMovieDbService
.searchMovies(searchQuery)
.subscribe((tmdbMovieResponse) => this._movies.next(tmdbMovieResponse));
}
}
28 changes: 13 additions & 15 deletions src/app/views/home/home.component.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<!-- A mat toolbar with a span, spacer, and two mat buttons: -->
<mat-toolbar color="primary">
<span>Movie Search</span>
<span class="spacer"></span>

<button color="accent" mat-icon-button title="Search" routerLink="/search">
<mat-icon>search</mat-icon>
</button>
<span class="gutter-item">
<button
[hidden]="router.url === '/search'"
color="accent"
mat-icon-button
title="Search"
routerLink="/search"
>
<mat-icon>arrow_back</mat-icon>
</button>
</span>

<button
color="accent"
mat-icon-button
title="Movie Detail"
routerLink="/movie-detail"
>
<mat-icon>movie</mat-icon>
</button>
<span>Movie Search</span>
<span class="gutter-item"></span>
</mat-toolbar>

<main>
20 changes: 14 additions & 6 deletions src/app/views/home/home.component.scss
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
// mat toolbar with spacer css:
:host {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
}

.mat-toolbar {
display: flex;
justify-content: space-between;
height: 40px;
}
padding: 0px;
height: 40px !important;

// spacer:
.spacer {
flex: 1 1 auto;
span.gutter-item {
width: 50px;
}
}

main {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
width: var(--margin-pct);
}
6 changes: 4 additions & 2 deletions src/app/views/home/home.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { Router, RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
@@ -20,4 +20,6 @@ import { MatToolbarModule } from '@angular/material/toolbar';
styleUrl: './home.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HomeComponent {}
export class HomeComponent {
public constructor(public router: Router) {}
}
26 changes: 25 additions & 1 deletion src/app/views/search/search.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
<p>search works!</p>
<div>
<mat-form-field class="example-form-field">
<mat-label>Search</mat-label>
<input matInput id="name" type="text" [formControl]="searchFormControl" />
@if (searchFormControl.value) {
<button
matSuffix
mat-icon-button
aria-label="Clear"
(click)="searchFormControl.reset()"
>
<mat-icon>close</mat-icon>
</button>
}
</mat-form-field>
</div>
<div>
<ul>
@for (movie of (movieStoreService.movies$ | async)?.results; track movie) {
<li>
{{ movie.title }}
</li>
}
</ul>
</div>
8 changes: 8 additions & 0 deletions src/app/views/search/search.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
:host {
width: 100%;
height: var(--margin-pct);

* {
width: 100%;
}
}
32 changes: 30 additions & 2 deletions src/app/views/search/search.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
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 { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { debounce, debounceTime } from 'rxjs';

@Component({
selector: 'mose-search',
standalone: true,
imports: [CommonModule],
imports: [
CommonModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
FormsModule,
MatButtonModule,
MatIconModule,
],
templateUrl: './search.component.html',
styleUrl: './search.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SearchComponent {}
export class SearchComponent {
public searchFormControl = new FormControl('');

public constructor(public movieStoreService: MovieStoreService) {
this.searchFormControl.valueChanges
.pipe(debounceTime(500))
.subscribe((searchQuery) => {
// TODO: Add in a filter operator:
if (searchQuery) {
this.movieStoreService.searchMovies(searchQuery);
}
});
}
}
2 changes: 2 additions & 0 deletions src/styles.scss
Original file line number Diff line number Diff line change
@@ -10,6 +10,8 @@ body {
}

:root {
--margin-pct: 95%;

// TODO: Add in global CSS4 variables:
.light-mode {
// TODO: In future we can overide the same CSS4 variable when the light-mode class is on the body in the index.html