mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
[HIMA-26] Finished implementing dashboard feed
This commit is contained in:
@@ -6,11 +6,11 @@ import { FeedRecommandation } from 'src/app/core/models/feed-recommandation.mode
|
||||
|
||||
export const feedMock: FeedCard[] = <FeedCard[]> [
|
||||
<FeedCard> {
|
||||
id: 1,
|
||||
id: '1',
|
||||
cardTitle: 'BESTSELLER',
|
||||
type: 'BOOK',
|
||||
books: <FeedBook> {
|
||||
id: 1,
|
||||
id: '1',
|
||||
firstBookAuthor: 'Michelle Obama',
|
||||
firstBookTitle: 'Becoming Meine Geschichte',
|
||||
firstBookType: 'B',
|
||||
@@ -26,29 +26,29 @@ export const feedMock: FeedCard[] = <FeedCard[]> [
|
||||
}
|
||||
},
|
||||
<FeedCard> {
|
||||
id: 2,
|
||||
id: '2',
|
||||
cardTitle: 'EVENT',
|
||||
type: 'EVENT',
|
||||
event: <FeedEvent> {
|
||||
event: <FeedEvent[]> [{
|
||||
id: 1,
|
||||
title: 'Lesung Manfred Bomm',
|
||||
// tslint:disable-next-line:max-line-length
|
||||
content: 'Möchten Sie an der Lesung des Krimiautors Manfred Bomm „Himmelsfelsen“ teilnehmen? Die Lesung findet am Dienstag, den 11.12.18 in der Filliale am Stachus in unserem große…'
|
||||
}
|
||||
}]
|
||||
},
|
||||
<FeedCard> {
|
||||
id: 3,
|
||||
id: '3',
|
||||
cardTitle: 'NEWS',
|
||||
type: 'NEWS',
|
||||
news: <FeedNews> {
|
||||
news: <FeedNews[]> [{
|
||||
id: 1,
|
||||
title: 'Neueröffnung am Stachus in München',
|
||||
// tslint:disable-next-line:max-line-length
|
||||
content: 'Sie sind das erste Mal nach der Neueröffnung in unserem Store? Entdecken Sie unsere neue Lesewelten, sowie neue interessante Veranstaltungen b…'
|
||||
}
|
||||
}]
|
||||
},
|
||||
<FeedCard> {
|
||||
id: 4,
|
||||
id: '4',
|
||||
cardTitle: 'EMPFEHLUNG',
|
||||
type: 'REC',
|
||||
recommandation: <FeedRecommandation> {
|
||||
@@ -59,11 +59,11 @@ export const feedMock: FeedCard[] = <FeedCard[]> [
|
||||
}
|
||||
},
|
||||
<FeedCard> {
|
||||
id: 5,
|
||||
id: '5',
|
||||
cardTitle: 'NEUERSCHEINUNG FANTASY',
|
||||
type: 'BOOK',
|
||||
books: <FeedBook> {
|
||||
id: 1,
|
||||
id: '1',
|
||||
firstBookAuthor: 'Joanne K. Rowling',
|
||||
firstBookTitle: 'Grindelwalds verbrechen',
|
||||
firstBookType: 'B',
|
||||
|
||||
@@ -105,7 +105,7 @@ export function _feedServiceEndpointProviderFactory(conf: ConfigService) {
|
||||
deps: [ConfigService]
|
||||
},
|
||||
// { provide: CatSearchService, useClass: CatSearchMockService }, // Uncomment if u want to use the CatSearchMockService
|
||||
{ provide: FeedService, useClass: FeedMockService } // Uncomment if u want to use the FeedMockService
|
||||
// { provide: FeedService, useClass: FeedMockService } // Uncomment if u want to use the FeedMockService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
72
src/app/core/mappings/feed.mapping.ts
Normal file
72
src/app/core/mappings/feed.mapping.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { FeedCard } from '../models/feed-card.model';
|
||||
import { FeedDTO } from 'feed-service';
|
||||
import { FeedBook } from '../models/feed-book.model';
|
||||
import { FeedEvent } from '../models/feed-event.model';
|
||||
import { FeedNews } from '../models/feed-news.model';
|
||||
import { FeedRecommandation } from '../models/feed-recommandation.model';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class FeedMapping {
|
||||
constructor () {}
|
||||
|
||||
fromFeedDTO (feed: FeedDTO): FeedCard {
|
||||
let books: FeedBook = null;
|
||||
const event: FeedEvent[] = [];
|
||||
const news: FeedNews[] = [];
|
||||
const recommandation: FeedRecommandation = null;
|
||||
|
||||
if (feed.type === 'products' && feed.items[0]) {
|
||||
books = {
|
||||
id: feed.id,
|
||||
firstBookTypeIcon: feed.items[0].pr.format,
|
||||
firstBookEan: feed.items[0].pr.ean,
|
||||
firstBookAuthor: feed.items[0].pr.name,
|
||||
firstBookTitle: feed.items[0].pr.additionalName,
|
||||
firstBookType: feed.items[0].pr.formatDetail,
|
||||
firstBookIcon: feed.items[0].pr.format,
|
||||
firstBookLanguage: feed.items[0].pr.locale,
|
||||
firstBookPrice: feed.items[0].av[0].price.value.value + ' ' + feed.items[0].av[0].price.value.currency
|
||||
};
|
||||
if (feed.items[1]) {
|
||||
books = {
|
||||
...books,
|
||||
secondBookEan: feed.items[1].pr.ean,
|
||||
secondBookAuthor: feed.items[1].pr.name,
|
||||
secondBookTitle: feed.items[1].pr.additionalName,
|
||||
secondBookType: feed.items[1].pr.formatDetail,
|
||||
secondBookTypeIcon: feed.items[1].pr.format,
|
||||
secondBookIcon: feed.items[1].pr.format,
|
||||
secondBookLanguage: feed.items[1].pr.locale,
|
||||
secondBookPrice: feed.items[1].av[0].price.value.value + ' ' + feed.items[0].av[0].price.value.currency
|
||||
};
|
||||
}
|
||||
} else if (feed.type === 'events') {
|
||||
feed.items.forEach (
|
||||
i => event.push(<FeedEvent> {
|
||||
id: i.id,
|
||||
title: i.name,
|
||||
content: i.desc
|
||||
})
|
||||
);
|
||||
} else if (feed.type === 'info') {
|
||||
feed.items.forEach (
|
||||
i => news.push(<FeedNews> {
|
||||
id: i.id,
|
||||
title: i.heading,
|
||||
content: i.text
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return <FeedCard> {
|
||||
id: feed.id,
|
||||
cardTitle: feed.label,
|
||||
type: feed.type,
|
||||
books: books,
|
||||
event: event,
|
||||
news: news,
|
||||
recommandation: recommandation
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,19 @@
|
||||
export interface FeedBook {
|
||||
id: number;
|
||||
id: string;
|
||||
firstBookEan: string;
|
||||
firstBookAuthor: string;
|
||||
firstBookTitle: string;
|
||||
firstBookType: string;
|
||||
firstBookTypeIcon: string;
|
||||
firstBookLanguage: string;
|
||||
firstBookPrice: string;
|
||||
firstBookIcon: string;
|
||||
secondBookAuthor: string;
|
||||
secondBookTitle: string;
|
||||
secondBookType: string;
|
||||
secondBookLanguage: string;
|
||||
secondBookPrice: string;
|
||||
secondBookIcon: string;
|
||||
secondBookEan?: string;
|
||||
secondBookAuthor?: string;
|
||||
secondBookTitle?: string;
|
||||
secondBookType?: string;
|
||||
secondBookTypeIcon?: string;
|
||||
secondBookLanguage?: string;
|
||||
secondBookPrice?: string;
|
||||
secondBookIcon?: string;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import { FeedNews } from './feed-news.model';
|
||||
import { FeedRecommandation } from './feed-recommandation.model';
|
||||
|
||||
export interface FeedCard {
|
||||
id: number;
|
||||
id: string;
|
||||
cardTitle: string;
|
||||
type: string;
|
||||
books: FeedBook;
|
||||
event: FeedEvent;
|
||||
news: FeedNews;
|
||||
event: FeedEvent[];
|
||||
news: FeedNews[];
|
||||
recommandation: FeedRecommandation;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ import { State, Selector, Action, StateContext } from '@ngxs/store';
|
||||
import { LoadFeed } from '../actions/feed.actions';
|
||||
import { feedMock } from 'mocks/feed.mock';
|
||||
import { FeedCard } from '../../models/feed-card.model';
|
||||
import { FeedService } from 'feed-service';
|
||||
import { FeedService, FeedDTO } from 'feed-service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { FeedMapping } from 'src/app/core/mappings/feed.mapping';
|
||||
import { PagedApiResponse } from 'projects/feed-service/src/lib';
|
||||
|
||||
export class FeedStateModel {
|
||||
feed: FeedCard[];
|
||||
@@ -16,7 +19,7 @@ export class FeedStateModel {
|
||||
})
|
||||
export class FeedState {
|
||||
|
||||
constructor(private feedService: FeedService) {}
|
||||
constructor(private feedService: FeedService, private feedMapping: FeedMapping) { }
|
||||
|
||||
@Selector()
|
||||
static getFeed(state: FeedStateModel) {
|
||||
@@ -26,13 +29,22 @@ export class FeedState {
|
||||
@Action(LoadFeed)
|
||||
load(ctx: StateContext<FeedStateModel>) {
|
||||
const state = ctx.getState();
|
||||
// TODO: implement api call to state
|
||||
// this.feedService.info().subscribe(
|
||||
// (feed: any) => console.log(feed)
|
||||
// );
|
||||
ctx.patchState({
|
||||
...state,
|
||||
feed: [...feedMock]
|
||||
});
|
||||
this.feedService.info().subscribe(
|
||||
(feed: PagedApiResponse<FeedDTO<any>>) => {
|
||||
console.log(feed);
|
||||
const feeds = feed.result.map(t =>
|
||||
this.feedMapping.fromFeedDTO(t)
|
||||
);
|
||||
console.log(feeds);
|
||||
ctx.patchState({
|
||||
...state,
|
||||
feed: [...feeds]
|
||||
});
|
||||
}
|
||||
);
|
||||
// ctx.patchState({
|
||||
// ...state,
|
||||
// feed: [...feedMock]
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
<div class="card-title align-left">
|
||||
<span>{{card.cardTitle}}</span>
|
||||
</div>
|
||||
<div class="card-items">
|
||||
<div class="card-items" [ngClass]="{'single-item-mode': !card.books.secondBookAuthor}">
|
||||
<div class="item align-left">
|
||||
<div class="item-logo">
|
||||
<img class="book-image" src="../../../assets/images/{{card.books.firstBookIcon}}">
|
||||
<img class="book-image" [src]='firstBookImageUrl$ | async'>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<div class="book-author wrap-text-more">{{card.books.firstBookAuthor}}</div>
|
||||
<div class="book-title wrap-text-more">{{card.books.firstBookTitle}}</div>
|
||||
<div class="item-detail">
|
||||
<div class="book-type">
|
||||
<div><img class="book-type-icon" src="../../../assets/images/Icon_Book.svg"></div>
|
||||
<div class="item-detail" [ngClass]="{'single-item-detail-mode': !card.books.secondBookAuthor}">
|
||||
<div class="book-type" [ngClass]="{'book-type-single-mode': !card.books.secondBookAuthor}">
|
||||
<div><img class="book-type-icon" src="../../../assets/images/Icon_{{card.books.firstBookTypeIcon}}.svg"></div>
|
||||
<div class="item-detail wrap-text-more">{{card.books.firstBookType}}</div>
|
||||
<div class="separator">|</div>
|
||||
</div>
|
||||
<div class="book-language">
|
||||
<div class="book-language" [ngClass]="{'book-language-single-mode': !card.books.secondBookAuthor}">
|
||||
<div class="item-details wrap-text-more">{{card.books.firstBookLanguage}}</div>
|
||||
<div class="separator">|</div>
|
||||
</div>
|
||||
@@ -24,16 +24,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item align-left">
|
||||
<div class="item align-left" *ngIf="card.books.secondBookAuthor">
|
||||
<div class="item-logo">
|
||||
<img class="book-image" src="../../../assets/images/{{card.books.secondBookIcon}}">
|
||||
<img class="book-image" [src]='secondBookImageUrl$ | async'>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<div class="book-author wrap-text-more">{{card.books.secondBookAuthor}}</div>
|
||||
<div class="book-title wrap-text-more">{{card.books.secondBookTitle}}</div>
|
||||
<div class="item-detail">
|
||||
<div class="book-type">
|
||||
<div><img class="book-type-icon" src="../../../assets/images/Icon_Book.svg"></div>
|
||||
<div><img class="book-type-icon" src="../../../assets/images/Icon_{{card.books.secondBookTypeIcon}}.svg"></div>
|
||||
<div class="item-detail wrap-text-more">{{card.books.secondBookType}}</div>
|
||||
<div class="separator">|</div>
|
||||
</div>
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.single-item-mode {
|
||||
grid-template-columns: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 563px) {
|
||||
.card-items {
|
||||
display: grid;
|
||||
@@ -53,6 +57,11 @@
|
||||
grid-template-columns: auto auto auto;
|
||||
}
|
||||
|
||||
.single-item-detail-mode {
|
||||
grid-template-columns: max-content max-content auto;
|
||||
grid-gap: 2vh;
|
||||
}
|
||||
|
||||
.book-author {
|
||||
height: 21px;
|
||||
font-size: 16px;
|
||||
@@ -70,6 +79,10 @@
|
||||
grid-template-columns: auto auto auto;
|
||||
}
|
||||
|
||||
.book-type-single-mode {
|
||||
grid-gap: 1vh;
|
||||
}
|
||||
|
||||
.separator .item-details {
|
||||
height: 21px;
|
||||
font-size: 16px;
|
||||
@@ -80,3 +93,11 @@
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
}
|
||||
|
||||
.book-language-single-mode {
|
||||
grid-gap: 1vh;
|
||||
}
|
||||
|
||||
.book-type-icon {
|
||||
margin-top: 2px;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FeedCard } from 'src/app/core/models/feed-card.model';
|
||||
import { CatImageService } from 'cat-service';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-card',
|
||||
@@ -9,10 +11,20 @@ import { FeedCard } from 'src/app/core/models/feed-card.model';
|
||||
export class BookCardComponent implements OnInit {
|
||||
|
||||
@Input() card: FeedCard;
|
||||
firstBookImageUrl$: Observable<string>;
|
||||
secondBookImageUrl$: Observable<string>;
|
||||
|
||||
constructor() { }
|
||||
constructor(private catImageService: CatImageService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.catImageService.getImageUrl(this.card.books.firstBookEan).subscribe(
|
||||
(url: string) => this.firstBookImageUrl$ = of(url)
|
||||
);
|
||||
if (this.card.books.secondBookEan) {
|
||||
this.catImageService.getImageUrl(this.card.books.secondBookEan).subscribe(
|
||||
(url: string) => this.secondBookImageUrl$ = of(url)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div class="card-container">
|
||||
<div class="card-container" *ngFor="let event of card.event">
|
||||
<div class="card-title align-left">
|
||||
<span>{{card.cardTitle}}</span>
|
||||
</div>
|
||||
<div class="event-title align-left wrap-text-more">
|
||||
<span>{{card.event.title}}</span>
|
||||
<span [innerHTML]='event.title'></span>
|
||||
</div>
|
||||
<div class="event-content align-left">
|
||||
<span>{{card.event.content}}</span>
|
||||
<span [innerHTML]='event.content'></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +1,16 @@
|
||||
<div class="card-container">
|
||||
<div class="card-icon-container align-center">
|
||||
<div class="card-container card-container-no-image" *ngFor="let news of card.news">
|
||||
<!-- <div class="card-icon-container align-center">
|
||||
<img class="news-icon" src="../../../assets/images/News_Icon.svg">
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="card-content-container">
|
||||
<div class="card-title align-left">
|
||||
<span>{{card.cardTitle}}</span>
|
||||
</div>
|
||||
<div class="news-title align-left wrap-text-more">
|
||||
<span>{{card.news.title}}</span>
|
||||
<span>{{news.title}}</span>
|
||||
</div>
|
||||
<div class="news-content align-left">
|
||||
<span>{{card.news.content}}</span>
|
||||
<span>{{news.content}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -13,6 +13,10 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.card-container-no-image {
|
||||
grid-template-columns: auto;
|
||||
}
|
||||
|
||||
.card-content-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div *ngFor="let card of feed$ | async">
|
||||
<app-book-card *ngIf="card.type === 'BOOK'" [card]="card"></app-book-card>
|
||||
<app-event-card *ngIf="card.type === 'EVENT'" [card]="card"></app-event-card>
|
||||
<app-news-card *ngIf="card.type === 'NEWS'" [card]="card"></app-news-card>
|
||||
<app-book-card *ngIf="card.type === 'products'" [card]="card"></app-book-card>
|
||||
<app-event-card *ngIf="card.type === 'events'" [card]="card"></app-event-card>
|
||||
<app-news-card *ngIf="card.type === 'info'" [card]="card"></app-news-card>
|
||||
<app-recommandation-card *ngIf="card.type === 'REC'" [card]="card"></app-recommandation-card>
|
||||
</div>
|
||||
</div>
|
||||
<app-loading [loading]="loading" text="Inhalte werden geladen"></app-loading>
|
||||
@@ -12,6 +12,8 @@ import { FeedState } from 'src/app/core/store/state/feed.state';
|
||||
})
|
||||
export class DashboardComponent implements OnInit {
|
||||
|
||||
loading = true;
|
||||
|
||||
@Select(FeedState.getFeed) feed$: Observable<FeedCard[]>;
|
||||
constructor(
|
||||
private store: Store
|
||||
@@ -19,5 +21,8 @@ export class DashboardComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.store.dispatch(new LoadFeed());
|
||||
this.feed$.subscribe(
|
||||
() => this.loading = false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ import { BookCardComponent } from './components/book-card/book-card.component';
|
||||
import { EventCardComponent } from './components/event-card/event-card.component';
|
||||
import { NewsCardComponent } from './components/news-card/news-card.component';
|
||||
import { RecommandationCardComponent } from './components/recommandation-card/recommandation-card.component';
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
imports: [CommonModule, SharedModule],
|
||||
exports: [DashboardComponent],
|
||||
declarations: [
|
||||
DashboardComponent,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700" rel="stylesheet">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700" rel="stylesheet">
|
||||
|
||||
Reference in New Issue
Block a user