Skip to content

Commit

Permalink
Merge pull request #11 from oidacra/add-search-component
Browse files Browse the repository at this point in the history
feat(search-series): add search serie at home page
  • Loading branch information
oidacra authored Apr 1, 2024
2 parents b07bb52 + 2766d0d commit 52b0585
Show file tree
Hide file tree
Showing 34 changed files with 678 additions and 206 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
}
]
}
],
"no-console": [
"error",
{
"allow": ["warn", "error"]
}
]
}
},
Expand Down
10 changes: 9 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
{
"singleQuote": true
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"semi": true,
"bracketSpacing": true,
"arrowParens": "always",
"trailingComma": "es5",
"bracketSameLine": true,
"printWidth": 80
}
27 changes: 3 additions & 24 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
/* eslint-disable */
import { getJestProjects } from '@nx/jest';

export default {
displayName: 'series-workspace',
preset: './jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: './coverage/series-workspace',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
testMatch: [
'<rootDir>/src/**/__tests__/**/*.[jt]s?(x)',
'<rootDir>/src/**/*(*.)@(spec|test).[jt]s?(x)',
],
projects: getJestProjects(),
};
15 changes: 14 additions & 1 deletion nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
"{workspaceRoot}/eslint.config.js"
],
"cache": true
},
"@nx/angular:ng-packagr-lite": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
},
"namedInputs": {
Expand Down Expand Up @@ -63,5 +68,13 @@
}
},
"defaultProject": "series-workspace",
"nxCloudAccessToken": "YzFkMzY0ZjItY2IzZi00ZDc5LTk4MzctMGZmZjNjZmE3ZGNlfHJlYWQtd3JpdGU="
"nxCloudAccessToken": "YzFkMzY0ZjItY2IzZi00ZDc5LTk4MzctMGZmZjNjZmE3ZGNlfHJlYWQtd3JpdGU=",
"plugins": [
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "lint"
}
}
]
}
2 changes: 1 addition & 1 deletion project.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectName}"],
"options": {
"jestConfig": "jest.config.ts"
"jestConfig": "jest.config.app.ts"
}
}
}
Expand Down
9 changes: 2 additions & 7 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
<nz-layout class="layout">
<nz-header>
<div class="logo"></div>
<ul nz-menu nzMode="horizontal" nzTheme="dark">
<li nz-menu-item>nav 1</li>
<li nz-menu-item>nav 2</li>
<li nz-menu-item>nav 3</li>
</ul>
<div class="logo">TV Series</div>
</nz-header>
<nz-content>
<div class="inner-content">
<div class="content">
<router-outlet></router-outlet>
</div>
</nz-content>
Expand Down
17 changes: 4 additions & 13 deletions src/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
}

.logo {
width: 120px;
height: 31px;
background: rgba(255, 255, 255, 0.2);
margin: 16px 24px 16px 0;
float: left;
color: white;
font-size: 1rem;
}

nz-header {
Expand All @@ -25,14 +22,8 @@ nz-content {
margin-top: 64px;
}

nz-breadcrumb {
margin: 16px 0;
}

.inner-content {
background: #fff;
padding: 24px;
min-height: 380px;
.content {
display: flex;
}

nz-footer {
Expand Down
9 changes: 2 additions & 7 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,15 @@ import {
NzHeaderComponent,
NzLayoutComponent,
} from 'ng-zorro-antd/layout';
import { NzBreadCrumbComponent } from 'ng-zorro-antd/breadcrumb';
import { NzMenuDirective, NzMenuItemComponent } from 'ng-zorro-antd/menu';

@Component({
standalone: true,
imports: [
RouterModule,
NzLayoutComponent,
NzHeaderComponent,
NzContentComponent,
NzBreadCrumbComponent,
NzFooterComponent,
NzHeaderComponent,
NzLayoutComponent,
NzMenuDirective,
NzMenuItemComponent,
],
selector: 'app-root',
templateUrl: './app.component.html',
Expand Down
17 changes: 15 additions & 2 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@ import { Route } from '@angular/router';

export const appRoutes: Route[] = [
{
path: '',
path: 'search',
loadComponent: () =>
import('./series/series.component').then((m) => m.SeriesComponent),
import('./series/search/search-container.component').then(
(m) => m.SearchContainerComponent
),
},
// All empty paths should redirect to the search page
{
path: '',
pathMatch: 'full',
redirectTo: 'search',
},
// All other paths should redirect to the search page too
{
path: '**',
redirectTo: 'search',
},
];
42 changes: 42 additions & 0 deletions src/app/series/search/components/results/results.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@if (state() === 'loaded'){
<span nz-typography nzType="secondary">{{ series().length }} items found</span>

<div class="series-card__wrapper">
@for (item of series(); track item.show.id; ) {

<nz-card nzHoverable [nzCover]="coverTemplate" data-testId="series-card">
<nz-card-meta [nzTitle]="cardTitle" />
</nz-card>

<!-- Cover template for the card -->
<ng-template #coverTemplate>
@if (item.show.image){
<img
data-testId="poster-image"
loading="lazy"
width="210"
height="295"
[alt]="item.show.name"
[ngSrc]="item.show.image.medium" />
} @else {
<span
data-testId="poster-image-not-found"
class="series-card__poster-not-found"
>No Poster Found</span
>
}
</ng-template>

<!-- Title template for the card -->
<ng-template #cardTitle>
<span data-testId="poster-title">{{ item.show.name }}</span>
</ng-template>

} @empty {
<nz-empty nzNotFoundContent="No TV Series found"></nz-empty>
}
</div>
}@else {
<nz-empty
nzNotFoundContent="Use the search for find you favorite TV Show"></nz-empty>
}
32 changes: 32 additions & 0 deletions src/app/series/search/components/results/results.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
:host {
display: flex;
flex-direction: column;
gap: 24px;

.series-card__poster-not-found {
width: 210px;
height: 295px;
display: flex;
justify-content: center;
align-items: center;
}

.series-card__wrapper {
display: flex;
flex-wrap: wrap;
width: 100%;
justify-content: space-around;
gap: 2rem;
}

::ng-deep {
[nz-card] {
width: 210px;
flex: 0 0 auto;
}

[nz-typography] {
text-align: right;
}
}
}
62 changes: 62 additions & 0 deletions src/app/series/search/components/results/results.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ResultsComponent } from './results.component';
import { By } from '@angular/platform-browser';
import { NzEmptyComponent } from 'ng-zorro-antd/empty';
import { DebugElement } from '@angular/core';
import { SeriesMock } from '../../../tests/series.mocks';

describe('ResultsComponent', () => {
let component: ResultsComponent;
let fixture: ComponentFixture<ResultsComponent>;
let de: DebugElement;
let cardsElements: DebugElement[];

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ResultsComponent],
}).compileComponents();

fixture = TestBed.createComponent(ResultsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
fixture.componentRef.setInput('series', SeriesMock);
fixture.componentRef.setInput('state', 'loaded');
fixture.detectChanges();
cardsElements = fixture.debugElement.queryAll(
By.css('nz-card[data-testId="series-card"]')
);
});

it('should create nz-card with the correct number of items', () => {
expect(cardsElements.length).toBe(SeriesMock.length);
});

it('should show the correct title in nz-card-meta', () => {
const posterTitle = cardsElements[0].query(
By.css('[data-testId="poster-title"]')
);
expect(posterTitle).toBeTruthy();
expect(posterTitle.nativeElement.innerHTML).toContain(
SeriesMock[0].show.name
);
});

it('should show the correct medium image in nz-card', () => {
const posterImage = cardsElements[0].query(
By.css('[data-testId="poster-image"]')
);
expect(posterImage).toBeTruthy();
expect(posterImage.properties['src']).toEqual(
SeriesMock[0].show.image.medium
);
});

it('should show empty component when `series` input is empty array', () => {
fixture.componentRef.setInput('series', []);
fixture.detectChanges();
const emptyComponent = fixture.debugElement.query(
By.directive(NzEmptyComponent)
);
expect(emptyComponent).toBeTruthy();
});
});
36 changes: 36 additions & 0 deletions src/app/series/search/components/results/results.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
ChangeDetectionStrategy,
Component,
computed,
input,
output,
} from '@angular/core';
import { CommonModule, NgOptimizedImage } from '@angular/common';
import { NzEmptyComponent } from 'ng-zorro-antd/empty';
import { NzCardComponent, NzCardMetaComponent } from 'ng-zorro-antd/card';
import { NzPaginationComponent } from 'ng-zorro-antd/pagination';
import { ComponentState, Serie } from '../../../../shared/models';
import { NzTypographyComponent } from 'ng-zorro-antd/typography';

@Component({
selector: 'app-results',
standalone: true,
imports: [
CommonModule,
NzEmptyComponent,
NzCardComponent,
NzCardMetaComponent,
NzPaginationComponent,
NgOptimizedImage,
NzTypographyComponent,
],
templateUrl: './results.component.html',
styleUrl: './results.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ResultsComponent {
series = input<Serie[]>([]);
state = input<ComponentState>('idle');
isLoading = computed(() => this.state() === 'loading');
selected = output<Serie>();
}
Loading

0 comments on commit 52b0585

Please sign in to comment.