Skip to content

Commit 0d32deb

Browse files
Ismaestroiramos
authored andcommitted
feat(hero card): add hero card component
1 parent e372e82 commit 0d32deb

File tree

10 files changed

+152
-95
lines changed

10 files changed

+152
-95
lines changed

src/app/modules/heroes/pages/hero-detail-page/hero-detail-page.component.html

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,7 @@ <h1 class="header__title">{{'heroDetail' | translate}}</h1>
66
</mat-progress-spinner>
77
<div id="heroe-detail" *ngIf="hero">
88
<ng-container>
9-
<mat-card class="hero-card">
10-
<mat-card-header>
11-
<div mat-card-avatar class="hero-header__image"
12-
[ngStyle]="{'background-image': 'url(https://github.com/assets/images/heroes/'%20+%20hero.id%20+%20'-thumbnail.jpg)'}"></div>
13-
<mat-card-title>{{hero.name}}</mat-card-title>
14-
<mat-card-subtitle>{{hero.alterEgo}}</mat-card-subtitle>
15-
<div class="flex-spacer"></div>
16-
<div class="hero-actions">
17-
{{hero.likes}}
18-
<mat-icon matTooltip="{{(canVote ? 'canVote' : 'cannotVote') | translate}}"
19-
[matTooltipPosition]="'above'"
20-
class="icon__like--red" (click)="like(hero)">favorite
21-
</mat-icon>
22-
</div>
23-
</mat-card-header>
24-
<img mat-card-image src="assets/images/heroes/{{hero.id}}.jpg">
25-
</mat-card>
26-
9+
<app-hero-card [hero]="hero"></app-hero-card>
2710
<div id="hero-json">
2811
<pre>{{hero | json}}</pre>
2912
</div>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<mat-card class="hero-card" *ngIf="hero">
2+
<mat-card-header>
3+
<div (click)="seeHeroDetails(hero)" mat-card-avatar class="hero-header__image"
4+
[ngStyle]="{'background-image': 'url(https://github.com/assets/images/heroes/'%20+%20hero.id%20+%20'-thumbnail.jpg)'}"></div>
5+
<mat-card-title (click)="seeHeroDetails(hero)">{{hero.name}}</mat-card-title>
6+
<mat-card-subtitle (click)="seeHeroDetails(hero)">{{hero.alterEgo}}</mat-card-subtitle>
7+
<div class="flex-spacer"></div>
8+
<div class="hero-actions">
9+
{{hero.likes}}
10+
<mat-icon matTooltip="{{(canVote ? 'canVote' : 'cannotVote') | translate}}"
11+
[matTooltipPosition]="'above'"
12+
class="icon__like--red" (click)="like(hero)">favorite
13+
</mat-icon>
14+
</div>
15+
</mat-card-header>
16+
<img (click)="seeHeroDetails(hero)" mat-card-image src="assets/images/heroes/{{hero.id}}.jpg">
17+
</mat-card>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@import "mixins";
2+
@import "colors";
3+
4+
.hero-header__image, mat-card-title, mat-card-subtitle, .mat-card-image {
5+
cursor: pointer;
6+
}
7+
8+
.hero-card {
9+
margin-bottom: 2rem;
10+
@include push--auto(2rem);
11+
}
12+
13+
.progress__spinner {
14+
@include push--auto();
15+
}
16+
17+
@media (max-width: 680px) {
18+
.hero-card {
19+
width: 80%;
20+
@include push--auto();
21+
}
22+
23+
.mat-card {
24+
margin-bottom: 2rem;
25+
}
26+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2+
import {HeroCardComponent} from './hero-card.component';
3+
import {HeroService} from '../../../modules/heroes/shared/hero.service';
4+
import {APP_CONFIG, AppConfig} from '../../../configs/app.config';
5+
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
6+
import {APP_BASE_HREF} from '@angular/common';
7+
import {TestsModule} from '../../modules/tests.module';
8+
import {Hero} from '../../../modules/heroes/shared/hero.model';
9+
import {TranslateModule} from '@ngx-translate/core';
10+
11+
describe('HeroCardComponent', () => {
12+
let component: HeroCardComponent;
13+
let fixture: ComponentFixture<HeroCardComponent>;
14+
15+
beforeEach(async(() => {
16+
TestBed.configureTestingModule({
17+
imports: [
18+
TestsModule,
19+
TranslateModule.forRoot()
20+
],
21+
declarations: [
22+
HeroCardComponent
23+
],
24+
providers: [
25+
{provide: APP_CONFIG, useValue: AppConfig},
26+
{provide: APP_BASE_HREF, useValue: '/'},
27+
HeroService
28+
],
29+
schemas: [CUSTOM_ELEMENTS_SCHEMA]
30+
})
31+
.compileComponents();
32+
}));
33+
34+
beforeEach(() => {
35+
fixture = TestBed.createComponent(HeroCardComponent);
36+
component = fixture.componentInstance;
37+
fixture.detectChanges();
38+
});
39+
40+
it('should create', () => {
41+
expect(component).toBeTruthy();
42+
});
43+
44+
it('should like a hero', () => {
45+
localStorage.setItem('votes', String(AppConfig.votesLimit - 1));
46+
component.like(new Hero(1, '', '', 0)).then((result) => {
47+
expect(result).toBe(true);
48+
});
49+
});
50+
51+
it('should not like a hero', () => {
52+
localStorage.setItem('votes', String(AppConfig.votesLimit));
53+
component.like(new Hero(1, '', '', 0)).then(() => {
54+
}, (error) => {
55+
expect(error).toBe('maximum votes');
56+
});
57+
expect(HeroService.checkIfUserCanVote()).toBe(false);
58+
});
59+
});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {Component, Input, OnInit} from '@angular/core';
2+
import {AppConfig} from '../../../configs/app.config';
3+
import {HeroService} from '../../../modules/heroes/shared/hero.service';
4+
import {Hero} from '../../../modules/heroes/shared/hero.model';
5+
import {Router} from '@angular/router';
6+
7+
@Component({
8+
selector: 'app-hero-card',
9+
templateUrl: './hero-card.component.html',
10+
styleUrls: ['./hero-card.component.scss']
11+
})
12+
export class HeroCardComponent implements OnInit {
13+
14+
@Input() hero: Hero;
15+
16+
canVote = HeroService.checkIfUserCanVote();
17+
18+
constructor(private heroService: HeroService,
19+
private router: Router) {
20+
}
21+
22+
ngOnInit() {
23+
}
24+
25+
like(hero: Hero): Promise<any> {
26+
return new Promise((resolve, reject) => {
27+
this.heroService.like(hero).subscribe(() => {
28+
this.canVote = HeroService.checkIfUserCanVote();
29+
resolve(true);
30+
}, (error) => {
31+
reject(error);
32+
});
33+
});
34+
}
35+
36+
seeHeroDetails(hero): void {
37+
if (hero.default) {
38+
this.router.navigate([AppConfig.routes.heroes + '/' + hero.id]);
39+
}
40+
}
41+
42+
}

src/app/shared/pages/home-page/home-page.component.html

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,7 @@ <h1 class="header__title">{{'topHeroes' | translate}}</h1>
1818
</mat-card>
1919
<div id="heroes-list" *ngIf="heroes">
2020
<ng-container *ngFor="let hero of heroes">
21-
<mat-card class="hero-card">
22-
<mat-card-header>
23-
<div (click)="seeHeroDetails(hero)" mat-card-avatar class="hero-header__image"
24-
[ngStyle]="{'background-image': 'url(https://github.com/assets/images/heroes/'%20+%20hero.id%20+%20'-thumbnail.jpg)'}"></div>
25-
<mat-card-title (click)="seeHeroDetails(hero)">{{hero.name}}</mat-card-title>
26-
<mat-card-subtitle (click)="seeHeroDetails(hero)">{{hero.alterEgo}}</mat-card-subtitle>
27-
<div class="flex-spacer"></div>
28-
<div class="hero-actions">
29-
{{hero.likes}}
30-
<mat-icon matTooltip="{{(canVote ? 'canVote' : 'cannotVote') | translate}}"
31-
[matTooltipPosition]="'above'"
32-
class="icon__like--red" (click)="like(hero)">favorite
33-
</mat-icon>
34-
</div>
35-
</mat-card-header>
36-
<img (click)="seeHeroDetails(hero)" mat-card-image src="assets/images/heroes/{{hero.id}}.jpg">
37-
</mat-card>
21+
<app-hero-card [hero]="hero"></app-hero-card>
3822
</ng-container>
3923
</div>
4024
</div>

src/app/shared/pages/home-page/home-page.component.scss

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,3 @@
44
.hero-header__image, mat-card-title, mat-card-subtitle, .mat-card-image {
55
cursor: pointer;
66
}
7-
8-
.hero-card {
9-
margin-bottom: 2rem;
10-
@include push--auto(2rem);
11-
}
12-
13-
.progress__spinner {
14-
@include push--auto();
15-
}
16-
17-
@media (max-width: 680px) {
18-
.hero-card {
19-
width: 80%;
20-
@include push--auto();
21-
}
22-
23-
.mat-card {
24-
margin-bottom: 2rem;
25-
}
26-
}

src/app/shared/pages/home-page/home-page.component.spec.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,4 @@ describe('HomePage', () => {
4646
fixture.detectChanges();
4747
expect(component.heroes.length).toBe(AppConfig.topHeroesLimit);
4848
}));
49-
50-
it('should like a hero', async(() => {
51-
localStorage.setItem('votes', String(AppConfig.votesLimit - 1));
52-
component.like({id: 1}).then((result) => {
53-
expect(result).toBe(true);
54-
});
55-
}));
56-
57-
it('should not like a hero', async(() => {
58-
localStorage.setItem('votes', String(AppConfig.votesLimit));
59-
component.like({id: 1}).then(() => {
60-
}, (error) => {
61-
expect(error).toBe('maximum votes');
62-
});
63-
expect(HeroService.checkIfUserCanVote()).toBe(false);
64-
}));
6549
});
Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {Component, OnInit} from '@angular/core';
2-
import {Router} from '@angular/router';
32
import {Hero} from '../../../modules/heroes/shared/hero.model';
43
import {HeroService} from '../../../modules/heroes/shared/hero.service';
54
import {AppConfig} from '../../../configs/app.config';
@@ -12,11 +11,8 @@ import {AppConfig} from '../../../configs/app.config';
1211

1312
export class HomePageComponent implements OnInit {
1413
heroes: Hero[] = null;
15-
canVote = false;
1614

17-
constructor(private heroService: HeroService,
18-
private router: Router) {
19-
this.canVote = HeroService.checkIfUserCanVote();
15+
constructor(private heroService: HeroService) {
2016
}
2117

2218
ngOnInit() {
@@ -26,21 +22,4 @@ export class HomePageComponent implements OnInit {
2622
}).slice(0, AppConfig.topHeroesLimit);
2723
});
2824
}
29-
30-
like(hero: Hero): Promise<any> {
31-
return new Promise((resolve, reject) => {
32-
this.heroService.like(hero).subscribe(() => {
33-
this.canVote = HeroService.checkIfUserCanVote();
34-
resolve(true);
35-
}, (error) => {
36-
reject(error);
37-
});
38-
});
39-
}
40-
41-
seeHeroDetails(hero): void {
42-
if (hero.default) {
43-
this.router.navigate([AppConfig.routes.heroes + '/' + hero.id]);
44-
}
45-
}
4625
}

src/app/shared/shared.module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {ReactiveFormsModule} from '@angular/forms';
1212
import {RouterModule} from '@angular/router';
1313
import {HomePageComponent} from './pages/home-page/home-page.component';
1414
import {Error404PageComponent} from './pages/error404-page/error404-page.component';
15+
import {HeroCardComponent} from './components/hero-card/hero-card.component';
1516

1617
@NgModule({
1718
imports: [
@@ -29,7 +30,8 @@ import {Error404PageComponent} from './pages/error404-page/error404-page.compone
2930
HeaderComponent,
3031
SearchBarComponent,
3132
FooterComponent,
32-
SpinnerComponent
33+
SpinnerComponent,
34+
HeroCardComponent
3335
],
3436
exports: [
3537
CommonModule,
@@ -40,7 +42,8 @@ import {Error404PageComponent} from './pages/error404-page/error404-page.compone
4042
HeaderComponent,
4143
SearchBarComponent,
4244
FooterComponent,
43-
SpinnerComponent
45+
SpinnerComponent,
46+
HeroCardComponent
4447
]
4548
})
4649

0 commit comments

Comments
 (0)