diff --git a/README.md b/README.md index 246f55d..4407e0c 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,11 @@ This is an implementation of a Filmpire App using [The TMDB API](https://developer.themoviedb.org/docs) using: - Nx Workspace -- Angular v15 +- Angular v16 - Angular Material - NgRx - Tailwind CSS +- Storybook

(back to top)

diff --git a/apps/filmpire/src/app/app.routes.ts b/apps/filmpire/src/app/app.routes.ts index 293bc92..0d5df86 100644 --- a/apps/filmpire/src/app/app.routes.ts +++ b/apps/filmpire/src/app/app.routes.ts @@ -3,6 +3,7 @@ import { AccountComponent } from './account/account.component'; import { MediaInfoComponent } from './media-info/media-info.component'; import { MediaListComponent } from './media-list/media-list.component'; import { PersonInfoComponent } from './person-info/person-info.component'; +import { PageNotFoundComponent } from 'libs/ui/src/lib/page-not-found/page-not-found.component'; export const appRoutes: Route[] = [ { @@ -30,5 +31,5 @@ export const appRoutes: Route[] = [ component: AccountComponent, }, { path: '', redirectTo: 'category/movie/popular', pathMatch: 'full' }, - // { path: '**', component: PageNotFoundComponent }, // Wildcard route for a 404 page + { path: '**', component: PageNotFoundComponent }, // Wildcard route for a 404 page ]; diff --git a/libs/ui/.storybook/main.js b/libs/ui/.storybook/main.js index d883f9f..24da9b1 100644 --- a/libs/ui/.storybook/main.js +++ b/libs/ui/.storybook/main.js @@ -1,6 +1,6 @@ module.exports = { stories: ['../**/*.stories.mdx', '../**/*.stories.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], + addons: ['@storybook/addon-interactions', '@storybook/addon-essentials'], staticDirs: [{ from: '../src/assets', to: '/assets' }], framework: { diff --git a/libs/ui/.storybook/preview.js b/libs/ui/.storybook/preview.js index bf7cc79..a8418b9 100644 --- a/libs/ui/.storybook/preview.js +++ b/libs/ui/.storybook/preview.js @@ -1,4 +1,4 @@ -import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideHttpClient } from '@angular/common/http'; import { ReactiveFormsModule } from '@angular/forms'; import { provideAnimations } from '@angular/platform-browser/animations'; import { RouterModule } from '@angular/router'; @@ -6,7 +6,7 @@ import { applicationConfig } from '@storybook/angular'; export const decorators = [ applicationConfig({ - imports: [ReactiveFormsModule, RouterModule, HttpClientTestingModule], - providers: [provideAnimations()], + imports: [ReactiveFormsModule, RouterModule], + providers: [provideAnimations(), provideHttpClient()], }), ]; diff --git a/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.spec.ts b/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.spec.ts index d58fec9..c4d082c 100644 --- a/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.spec.ts +++ b/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.spec.ts @@ -1,6 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AutocompleteResultsComponent } from './autocomplete-results.component'; +import { MaterialModule } from '@ng-filmpire/material'; describe('AutocompleteResultsComponent', () => { let component: AutocompleteResultsComponent; @@ -8,6 +9,7 @@ describe('AutocompleteResultsComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ + imports: [MaterialModule], declarations: [AutocompleteResultsComponent], }).compileComponents(); diff --git a/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.stories.ts b/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.stories.ts new file mode 100644 index 0000000..ddfe363 --- /dev/null +++ b/libs/ui/src/lib/autocomplete-results/autocomplete-results.component.stories.ts @@ -0,0 +1,127 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { AutocompleteResultsComponent } from './autocomplete-results.component'; + +const meta: Meta = { + component: AutocompleteResultsComponent, + title: 'AutocompleteResultsComponent', +}; +export default meta; +type Story = StoryObj; + +export const Movie: Story = { + args: { + result: { + adult: false, + backdrop_path: '/rLb2cwF3Pazuxaj0sRXQ037tGI1.jpg', + id: 872585, + title: 'Oppenheimer', + original_language: 'en', + original_title: 'Oppenheimer', + overview: + 'The story of J. Robert Oppenheimer’s role in the development of the atomic bomb during World War II.', + poster_path: '/8Gxv8gSFCU0XGDykEGv7zR1n2ua.jpg', + media_type: 'movie', + genre_ids: [18, 36], + popularity: 704.491, + release_date: new Date('2023-07-19'), + video: false, + vote_average: 8.241, + vote_count: 4124, + }, + }, +}; + +export const TvShow: Story = { + args: { + result: { + adult: false, + backdrop_path: '/foGkPxpw9h8zln81j63mix5B7m8.jpg', + id: 71912, + name: 'The Witcher', + original_language: 'en', + original_name: 'The Witcher', + overview: + 'Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.', + poster_path: '/cZ0d3rtvXPVvuiX22sP79K3Hmjz.jpg', + media_type: 'tv', + genre_ids: [18, 10759, 10765], + popularity: 274.113, + first_air_date: new Date('2019-12-20'), + vote_average: 8.122, + vote_count: 5240, + origin_country: ['US'], + }, + }, +}; + +export const Person: Story = { + args: { + result: { + adult: false, + id: 73968, + name: 'Henry Cavill', + original_name: 'Henry Cavill', + media_type: 'person', + popularity: 59.828, + gender: 2, + known_for_department: 'Acting', + profile_path: '/iWdKjMry5Pt7vmxU7bmOQsIUyHa.jpg', + known_for: [ + { + adult: false, + backdrop_path: '/69EFgWWPFWbRNHmQgYdSnyJ94Ge.jpg', + id: 49521, + title: 'Man of Steel', + original_language: 'en', + original_title: 'Man of Steel', + overview: + 'A young boy learns that he has extraordinary powers and is not of this earth. As a young man, he journeys to discover where he came from and what he was sent here to do. But the hero in him must emerge if he is to save the world from annihilation and become the symbol of hope for all mankind.', + poster_path: '/dksTL9NXc3GqPBRHYHcy1aIwjS.jpg', + media_type: 'movie', + genre_ids: [28, 12, 878], + popularity: 48.081, + release_date: new Date('2013-06-12'), + video: false, + vote_average: 6.616, + vote_count: 14391, + }, + { + adult: false, + backdrop_path: '/5fX1oSGuYdKgwWmUTAN5MNSQGzr.jpg', + id: 209112, + title: 'Batman v Superman: Dawn of Justice', + original_language: 'en', + original_title: 'Batman v Superman: Dawn of Justice', + overview: + 'Fearing the actions of a god-like Super Hero left unchecked, Gotham City’s own formidable, forceful vigilante takes on Metropolis’s most revered, modern-day savior, while the world wrestles with what sort of hero it really needs. And with Batman and Superman at war with one another, a new threat quickly arises, putting mankind in greater danger than it’s ever known before.', + poster_path: '/5UsK3grJvtQrtzEgqNlDljJW96w.jpg', + media_type: 'movie', + genre_ids: [28, 12, 14], + popularity: 77.355, + release_date: new Date('2016-03-23'), + video: false, + vote_average: 5.955, + vote_count: 17163, + }, + { + adult: false, + backdrop_path: '/2nyaeISu2xIxIgZYNpX4UayY8PN.jpg', + id: 141052, + title: 'Justice League', + original_language: 'en', + original_title: 'Justice League', + overview: + "Fuelled by his restored faith in humanity and inspired by Superman's selfless act, Bruce Wayne and Diana Prince assemble a team of metahumans consisting of Barry Allen, Arthur Curry and Victor Stone to face the catastrophic threat of Steppenwolf and the Parademons who are on the hunt for three Mother Boxes on Earth.", + poster_path: '/eifGNCSDuxJeS1loAXil5bIGgvC.jpg', + media_type: 'movie', + genre_ids: [28, 12, 878], + popularity: 64.035, + release_date: new Date('2017-11-15'), + video: false, + vote_average: 6.095, + vote_count: 12316, + }, + ], + }, + }, +}; \ No newline at end of file diff --git a/libs/ui/src/lib/featured-media-slider/featured-media-slider.component.html b/libs/ui/src/lib/featured-media-slider/featured-media-slider.component.html index 57297f4..cdf362d 100644 --- a/libs/ui/src/lib/featured-media-slider/featured-media-slider.component.html +++ b/libs/ui/src/lib/featured-media-slider/featured-media-slider.component.html @@ -57,12 +57,9 @@
diff --git a/libs/ui/src/lib/media-card-item/media-card-item.component.html b/libs/ui/src/lib/media-card-item/media-card-item.component.html index 6ea36d2..b93194c 100644 --- a/libs/ui/src/lib/media-card-item/media-card-item.component.html +++ b/libs/ui/src/lib/media-card-item/media-card-item.component.html @@ -25,7 +25,7 @@ -

+

{{ (isMovie(media) ? media.release_date : media.first_air_date) | date : 'yyyy' @@ -34,10 +34,10 @@ class="mr-2 rounded bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900 dark:text-blue-300" >{{ (isMovie(media) ? 'movie' : 'tv') | uppercase }} -

+
+
+

Oops! Page Not Found

+

+ The page you are looking for might be in another scene. +

+ Go back to Homepage +
+ diff --git a/libs/ui/src/lib/page-not-found/page-not-found.component.scss b/libs/ui/src/lib/page-not-found/page-not-found.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/libs/ui/src/lib/page-not-found/page-not-found.component.spec.ts b/libs/ui/src/lib/page-not-found/page-not-found.component.spec.ts new file mode 100644 index 0000000..4171646 --- /dev/null +++ b/libs/ui/src/lib/page-not-found/page-not-found.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PageNotFoundComponent } from './page-not-found.component'; + +describe('PageNotFoundComponent', () => { + let component: PageNotFoundComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [PageNotFoundComponent] + }); + fixture = TestBed.createComponent(PageNotFoundComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/ui/src/lib/page-not-found/page-not-found.component.stories.ts b/libs/ui/src/lib/page-not-found/page-not-found.component.stories.ts new file mode 100644 index 0000000..815b33a --- /dev/null +++ b/libs/ui/src/lib/page-not-found/page-not-found.component.stories.ts @@ -0,0 +1,19 @@ +import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular'; +import { PageNotFoundComponent } from './page-not-found.component'; +import { MaterialModule } from '@ng-filmpire/material'; + +const meta: Meta = { + component: PageNotFoundComponent, + title: 'PageNotFoundComponent', + decorators: [ + moduleMetadata({ + imports: [MaterialModule], + }), + ], +}; +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: {}, +}; diff --git a/libs/ui/src/lib/page-not-found/page-not-found.component.ts b/libs/ui/src/lib/page-not-found/page-not-found.component.ts new file mode 100644 index 0000000..44c66d5 --- /dev/null +++ b/libs/ui/src/lib/page-not-found/page-not-found.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ng-filmpire-page-not-found', + templateUrl: './page-not-found.component.html', + styleUrls: ['./page-not-found.component.scss'] +}) +export class PageNotFoundComponent { + +} diff --git a/libs/ui/src/lib/ui.module.ts b/libs/ui/src/lib/ui.module.ts index 0edf27e..6a9db9e 100644 --- a/libs/ui/src/lib/ui.module.ts +++ b/libs/ui/src/lib/ui.module.ts @@ -10,6 +10,7 @@ import { MediaVideosDialogComponent } from './media-videos-dialog/media-videos-d import { NavbarComponent } from './navbar/navbar.component'; import { SidebarComponent } from './sidebar/sidebar.component'; import { AutocompleteResultsComponent } from './autocomplete-results/autocomplete-results.component'; +import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; @NgModule({ imports: [ CommonModule, @@ -26,6 +27,7 @@ import { AutocompleteResultsComponent } from './autocomplete-results/autocomplet MediaCardItemComponent, MediaVideosDialogComponent, AutocompleteResultsComponent, + PageNotFoundComponent, ], exports: [ NavbarComponent, @@ -33,6 +35,7 @@ import { AutocompleteResultsComponent } from './autocomplete-results/autocomplet MediaCardItemComponent, FeaturedMediaSliderComponent, MediaVideosDialogComponent, + PageNotFoundComponent, ], }) export class UiModule {} diff --git a/package.json b/package.json index 7e96a86..4db7dff 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,10 @@ "@ngrx/entity": "16.0.1", "@ngrx/router-store": "16.0.1", "@ngrx/store": "16.0.1", + "@nx/angular": "17.0.2", "rxjs": "~7.5.0", "tslib": "^2.3.0", - "zone.js": "0.13.3", - "@nx/angular": "17.0.2" + "zone.js": "0.13.3" }, "devDependencies": { "@angular-devkit/build-angular": "16.2.8", @@ -52,13 +52,20 @@ "@ngrx/schematics": "16.0.1", "@ngrx/store-devtools": "16.0.1", "@nx/cypress": "17.0.2", + "@nx/eslint": "17.0.2", + "@nx/eslint-plugin": "17.0.2", + "@nx/jest": "17.0.2", "@nx/js": "17.0.2", "@nx/storybook": "17.0.2", "@nx/workspace": "17.0.2", "@schematics/angular": "16.2.8", "@storybook/addon-essentials": "7.5.1", + "@storybook/addon-interactions": "^7.5.1", "@storybook/angular": "7.5.1", "@storybook/core-server": "7.5.1", + "@storybook/jest": "~0.1.0", + "@storybook/test-runner": "^0.13.0", + "@storybook/testing-library": "~0.2.0", "@types/jest": "29.5.6", "@types/node": "16.11.7", "@typescript-eslint/eslint-plugin": "5.60.1", @@ -84,9 +91,6 @@ "ts-jest": "29.1.1", "ts-node": "10.9.1", "typescript": "5.1.6", - "webpack": "^5.64.0", - "@nx/eslint": "17.0.2", - "@nx/jest": "17.0.2", - "@nx/eslint-plugin": "17.0.2" + "webpack": "^5.64.0" } }