mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merge remote-tracking branch 'origin/development' into feature/HIMA-50-create-address-change-screen
This commit is contained in:
@@ -6,11 +6,11 @@ import { FeedRecommandation } from 'src/app/core/models/feed-recommandation.mode
|
|||||||
|
|
||||||
export const feedMock: FeedCard[] = <FeedCard[]> [
|
export const feedMock: FeedCard[] = <FeedCard[]> [
|
||||||
<FeedCard> {
|
<FeedCard> {
|
||||||
id: 1,
|
id: '1',
|
||||||
cardTitle: 'BESTSELLER',
|
cardTitle: 'BESTSELLER',
|
||||||
type: 'BOOK',
|
type: 'BOOK',
|
||||||
books: <FeedBook> {
|
books: <FeedBook> {
|
||||||
id: 1,
|
id: '1',
|
||||||
firstBookAuthor: 'Michelle Obama',
|
firstBookAuthor: 'Michelle Obama',
|
||||||
firstBookTitle: 'Becoming Meine Geschichte',
|
firstBookTitle: 'Becoming Meine Geschichte',
|
||||||
firstBookType: 'B',
|
firstBookType: 'B',
|
||||||
@@ -26,29 +26,29 @@ export const feedMock: FeedCard[] = <FeedCard[]> [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
<FeedCard> {
|
<FeedCard> {
|
||||||
id: 2,
|
id: '2',
|
||||||
cardTitle: 'EVENT',
|
cardTitle: 'EVENT',
|
||||||
type: 'EVENT',
|
type: 'EVENT',
|
||||||
event: <FeedEvent> {
|
event: <FeedEvent[]> [{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: 'Lesung Manfred Bomm',
|
title: 'Lesung Manfred Bomm',
|
||||||
// tslint:disable-next-line:max-line-length
|
// 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…'
|
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> {
|
<FeedCard> {
|
||||||
id: 3,
|
id: '3',
|
||||||
cardTitle: 'NEWS',
|
cardTitle: 'NEWS',
|
||||||
type: 'NEWS',
|
type: 'NEWS',
|
||||||
news: <FeedNews> {
|
news: <FeedNews[]> [{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: 'Neueröffnung am Stachus in München',
|
title: 'Neueröffnung am Stachus in München',
|
||||||
// tslint:disable-next-line:max-line-length
|
// 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…'
|
content: 'Sie sind das erste Mal nach der Neueröffnung in unserem Store? Entdecken Sie unsere neue Lesewelten, sowie neue interessante Veranstaltungen b…'
|
||||||
}
|
}]
|
||||||
},
|
},
|
||||||
<FeedCard> {
|
<FeedCard> {
|
||||||
id: 4,
|
id: '4',
|
||||||
cardTitle: 'EMPFEHLUNG',
|
cardTitle: 'EMPFEHLUNG',
|
||||||
type: 'REC',
|
type: 'REC',
|
||||||
recommandation: <FeedRecommandation> {
|
recommandation: <FeedRecommandation> {
|
||||||
@@ -59,11 +59,11 @@ export const feedMock: FeedCard[] = <FeedCard[]> [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
<FeedCard> {
|
<FeedCard> {
|
||||||
id: 5,
|
id: '5',
|
||||||
cardTitle: 'NEUERSCHEINUNG FANTASY',
|
cardTitle: 'NEUERSCHEINUNG FANTASY',
|
||||||
type: 'BOOK',
|
type: 'BOOK',
|
||||||
books: <FeedBook> {
|
books: <FeedBook> {
|
||||||
id: 1,
|
id: '1',
|
||||||
firstBookAuthor: 'Joanne K. Rowling',
|
firstBookAuthor: 'Joanne K. Rowling',
|
||||||
firstBookTitle: 'Grindelwalds verbrechen',
|
firstBookTitle: 'Grindelwalds verbrechen',
|
||||||
firstBookType: 'B',
|
firstBookType: 'B',
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export function _feedServiceEndpointProviderFactory(conf: ConfigService) {
|
|||||||
deps: [ConfigService]
|
deps: [ConfigService]
|
||||||
},
|
},
|
||||||
// { provide: CatSearchService, useClass: CatSearchMockService }, // Uncomment if u want to use the CatSearchMockService
|
// { 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]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -345,7 +345,7 @@
|
|||||||
width: 13px;
|
width: 13px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
padding-right: 10px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
@@ -359,7 +359,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-delivery-info {
|
&-delivery-info {
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,6 +387,7 @@
|
|||||||
|
|
||||||
.dropdown-selected-text {
|
.dropdown-selected-text {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
&-active {
|
&-active {
|
||||||
background-color: #E9EDF9;
|
background-color: #E9EDF9;
|
||||||
|
|||||||
@@ -2,26 +2,34 @@
|
|||||||
<div class="menu-grid">
|
<div class="menu-grid">
|
||||||
<div class="menu-item-grid align-center" (click)="routeToMenu('/article-search', 'articlesearch')">
|
<div class="menu-item-grid align-center" (click)="routeToMenu('/article-search', 'articlesearch')">
|
||||||
<div>
|
<div>
|
||||||
<img class="menu-icon" *ngIf="router.url === '/article-search'; else articleSearchImageElse" src="/assets/images/Icon_Artikelsuche.svg">
|
<img class="menu-icon" *ngIf="router.url === '/article-search' ||
|
||||||
|
router.url.startsWith('/search-results') ||
|
||||||
|
router.url.startsWith('/product-details');
|
||||||
|
else articleSearchImageElse" src="/assets/images/Icon_Artikelsuche.svg">
|
||||||
<ng-template #articleSearchImageElse>
|
<ng-template #articleSearchImageElse>
|
||||||
<img class="menu-icon" src="/assets/images/Icon_Artikelsuche_inactive.svg">
|
<img class="menu-icon" src="/assets/images/Icon_Artikelsuche_inactive.svg">
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<span *ngIf="router.url === '/article-search'; else articleSearchLabelElse" class="menu-item selected">Artikelsuche</span>
|
<span *ngIf="router.url === '/article-search' ||
|
||||||
|
router.url.startsWith('/search-results') ||
|
||||||
|
router.url.startsWith('/product-details');
|
||||||
|
else articleSearchLabelElse" class="menu-item selected">Artikelsuche</span>
|
||||||
<ng-template #articleSearchLabelElse>
|
<ng-template #articleSearchLabelElse>
|
||||||
<span class="menu-item">Artikelsuche</span>
|
<span class="menu-item">Artikelsuche</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-item-grid align-center" (click)="routeToMenu('/customer-search', 'customersearch')">
|
<div class="menu-item-grid align-center" (click)="routeToMenu('/customer-search', 'customersearch')">
|
||||||
<div>
|
<div>
|
||||||
<img class="menu-icon" *ngIf="router.url === '/customer-search'; else customerSearchImageElse" src="/assets/images/Icon_Kundensuche.svg">
|
<img class="menu-icon" *ngIf="router.url === '/customer-search'; else customerSearchImageElse"
|
||||||
|
src="/assets/images/Icon_Kundensuche.svg">
|
||||||
<ng-template #customerSearchImageElse>
|
<ng-template #customerSearchImageElse>
|
||||||
<img class="menu-icon" src="/assets/images/Icon_Kundensuche_inactive.svg">
|
<img class="menu-icon" src="/assets/images/Icon_Kundensuche_inactive.svg">
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<span *ngIf="router.url === '/customer-search'; else customerSearchLabelElse" class="menu-item selected">Kundensuche</span>
|
<span *ngIf="router.url === '/customer-search'; else customerSearchLabelElse"
|
||||||
|
class="menu-item selected">Kundensuche</span>
|
||||||
<ng-template #customerSearchLabelElse>
|
<ng-template #customerSearchLabelElse>
|
||||||
<span class="menu-item">Kundensuche</span>
|
<span class="menu-item">Kundensuche</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-item-grid align-center">
|
<div class="menu-item-grid align-center">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
.menu-grid {
|
.menu-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto auto auto auto;
|
grid-template-columns: 20% 20% 20% 20% 20%;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="price align-right">
|
<div class="price align-right">
|
||||||
<span>{{ product.price }}</span>
|
<span>{{ price }}</span>
|
||||||
<span class="currency">{{ product.currency }}</span>
|
<span class="currency">{{ product.currency }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stock-container align-right">
|
<div class="stock-container align-right">
|
||||||
<div *ngIf="product.availability" class="available-stock">
|
<div *ngIf="product.itemsInStock > 0" class="available-stock">
|
||||||
<div class="available-icon-container">
|
<div class="available-icon-container">
|
||||||
<img
|
<img
|
||||||
class="available-icon"
|
class="available-icon"
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
<span>{{ product.itemsInStock }}x</span>
|
<span>{{ product.itemsInStock }}x</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!product.availability" class="not-available-stock">
|
<div *ngIf="product.itemsInStock === 0" class="not-available-stock">
|
||||||
<span>{{ product.notAvailableReason }}</span>
|
<span>{{ product.notAvailableReason }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="order">
|
<div class="order">
|
||||||
<span>{{ product.category }}</span>
|
<span>{{ product.location }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -123,4 +123,8 @@
|
|||||||
|
|
||||||
.type-icon-container {
|
.type-icon-container {
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.publisher {
|
||||||
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,13 @@ export class ProductCardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get price() {
|
||||||
|
if (this._product.price.toString().indexOf('.') === -1) {
|
||||||
|
return this._product.price + ',00';
|
||||||
|
}
|
||||||
|
return this._product.price.toString().replace('.', ',');
|
||||||
|
}
|
||||||
|
|
||||||
eanChangedSub = new ReplaySubject<string>();
|
eanChangedSub = new ReplaySubject<string>();
|
||||||
|
|
||||||
imageUrl$: Observable<string>;
|
imageUrl$: Observable<string>;
|
||||||
|
|||||||
@@ -35,10 +35,10 @@
|
|||||||
<div class="stock-label">
|
<div class="stock-label">
|
||||||
<span>Lieferbar</span>
|
<span>Lieferbar</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="home-icon">
|
<div class="home-icon" *ngIf="product.quantity > 0">
|
||||||
<img class="icon" src="../../../assets/images/Icon_House.svg">
|
<img class="icon" src="../../../assets/images/Icon_House.svg">
|
||||||
</div>
|
</div>
|
||||||
<div class="stock-quantity">
|
<div class="stock-quantity" *ngIf="product.quantity > 0">
|
||||||
<span>{{product.quantity}}</span>
|
<span>{{product.quantity}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
.type {
|
.type {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content auto;
|
grid-template-columns: min-content auto;
|
||||||
grid-gap: 10px;
|
grid-gap: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.type span {
|
.type span {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export class ProductDetailsComponent implements OnInit {
|
|||||||
if (item.pr) {
|
if (item.pr) {
|
||||||
ean = item.pr.ean;
|
ean = item.pr.ean;
|
||||||
eanTag = ean;
|
eanTag = ean;
|
||||||
productIcon$ = this.catImageService.getImageUrl(ean, { width: 469, height: 575});
|
productIcon$ = this.catImageService.getImageUrl(ean, { width: 469, height: 575 });
|
||||||
locale = item.pr.locale;
|
locale = item.pr.locale;
|
||||||
publicationDate = getFormatedPublicationDate(item.pr.publicationDate);
|
publicationDate = getFormatedPublicationDate(item.pr.publicationDate);
|
||||||
format = this.selectedItem ? this.selectedItem.pr.formatDetail : null;
|
format = this.selectedItem ? this.selectedItem.pr.formatDetail : null;
|
||||||
@@ -109,6 +109,11 @@ export class ProductDetailsComponent implements OnInit {
|
|||||||
if (item.av.length > 0) {
|
if (item.av.length > 0) {
|
||||||
quantity = (item.av[0].qty ? item.av[0].qty : 0) + 'x';
|
quantity = (item.av[0].qty ? item.av[0].qty : 0) + 'x';
|
||||||
price = item.av[0].price.value.value + ' ' + item.av[0].price.value.currency;
|
price = item.av[0].price.value.value + ' ' + item.av[0].price.value.currency;
|
||||||
|
if (item.av[0].price.value.value.toString().indexOf('.') === -1) {
|
||||||
|
price = item.av[0].price.value.value + ',00 ' + item.av[0].price.value.currency;
|
||||||
|
} else {
|
||||||
|
price = item.av[0].price.value.value.toString().replace('.', ',') + ' ' + item.av[0].price.value.currency;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
<app-product-card *ngFor="let product of products" [product]="product">
|
<app-product-card *ngFor="let product of products" [product]="product">
|
||||||
</app-product-card>
|
</app-product-card>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- [style.padding.px]="30" -->
|
||||||
<app-loading
|
<app-loading
|
||||||
[style.padding.px]="30"
|
loading="loading"
|
||||||
loading="true"
|
|
||||||
text="Inhalte werden geladen"
|
text="Inhalte werden geladen"
|
||||||
></app-loading>
|
></app-loading>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { ProductMapping } from 'src/app/core/mappings/product.mapping';
|
|||||||
export class SearchResultsComponent implements OnInit {
|
export class SearchResultsComponent implements OnInit {
|
||||||
currentSearch: Search;
|
currentSearch: Search;
|
||||||
products: Product[];
|
products: Product[];
|
||||||
|
loading = true;
|
||||||
@Select(ProcessState.getProducts) products$: Observable<ItemDTO[]>;
|
@Select(ProcessState.getProducts) products$: Observable<ItemDTO[]>;
|
||||||
skip = 0;
|
skip = 0;
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ export class SearchResultsComponent implements OnInit {
|
|||||||
private store: Store,
|
private store: Store,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private productMapping: ProductMapping
|
private productMapping: ProductMapping
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.loadCurrentSearch();
|
this.loadCurrentSearch();
|
||||||
@@ -67,6 +68,9 @@ export class SearchResultsComponent implements OnInit {
|
|||||||
filter(f => Array.isArray(f)),
|
filter(f => Array.isArray(f)),
|
||||||
map(items => items.map(item => this.productMapping.fromItemDTO(item)))
|
map(items => items.map(item => this.productMapping.fromItemDTO(item)))
|
||||||
)
|
)
|
||||||
.subscribe(data => (this.products = data));
|
.subscribe(
|
||||||
|
data => (this.products = data),
|
||||||
|
() => this.loading = false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/app/core/mappings/feed.mapping.ts
Normal file
74
src/app/core/mappings/feed.mapping.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
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,
|
||||||
|
firstBookCurrency: 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,
|
||||||
|
secondBookCurrency: feed.items[1].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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ export class FilterItemMapping {
|
|||||||
|
|
||||||
fromOptionDto(option: OptionDTO): FilterItem {
|
fromOptionDto(option: OptionDTO): FilterItem {
|
||||||
return {
|
return {
|
||||||
id: option.key,
|
id: option.value,
|
||||||
name: option.label,
|
name: option.label,
|
||||||
selected: false
|
selected: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class ProductMapping {
|
|||||||
err: '',
|
err: '',
|
||||||
category: item.pr.productGroup,
|
category: item.pr.productGroup,
|
||||||
icon: '',
|
icon: '',
|
||||||
notAvailableReason: '',
|
notAvailableReason: itemsInStock === 0 ? 'Not in stock' : '',
|
||||||
publisher: item.pr.manufacturer,
|
publisher: item.pr.manufacturer,
|
||||||
recommandation: false,
|
recommandation: false,
|
||||||
serial: item.pr.serial,
|
serial: item.pr.serial,
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
export interface FeedBook {
|
export interface FeedBook {
|
||||||
id: number;
|
id: string;
|
||||||
|
firstBookEan: string;
|
||||||
firstBookAuthor: string;
|
firstBookAuthor: string;
|
||||||
firstBookTitle: string;
|
firstBookTitle: string;
|
||||||
firstBookType: string;
|
firstBookType: string;
|
||||||
|
firstBookTypeIcon: string;
|
||||||
firstBookLanguage: string;
|
firstBookLanguage: string;
|
||||||
firstBookPrice: string;
|
firstBookPrice: string;
|
||||||
|
firstBookCurrency: string;
|
||||||
firstBookIcon: string;
|
firstBookIcon: string;
|
||||||
secondBookAuthor: string;
|
secondBookEan?: string;
|
||||||
secondBookTitle: string;
|
secondBookAuthor?: string;
|
||||||
secondBookType: string;
|
secondBookTitle?: string;
|
||||||
secondBookLanguage: string;
|
secondBookType?: string;
|
||||||
secondBookPrice: string;
|
secondBookTypeIcon?: string;
|
||||||
secondBookIcon: string;
|
secondBookLanguage?: string;
|
||||||
|
secondBookPrice?: string;
|
||||||
|
secondBookIcon?: string;
|
||||||
|
secondBookCurrency?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { FeedNews } from './feed-news.model';
|
|||||||
import { FeedRecommandation } from './feed-recommandation.model';
|
import { FeedRecommandation } from './feed-recommandation.model';
|
||||||
|
|
||||||
export interface FeedCard {
|
export interface FeedCard {
|
||||||
id: number;
|
id: string;
|
||||||
cardTitle: string;
|
cardTitle: string;
|
||||||
type: string;
|
type: string;
|
||||||
books: FeedBook;
|
books: FeedBook;
|
||||||
event: FeedEvent;
|
event: FeedEvent[];
|
||||||
news: FeedNews;
|
news: FeedNews[];
|
||||||
recommandation: FeedRecommandation;
|
recommandation: FeedRecommandation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,18 @@ import { Observable, of } from 'rxjs';
|
|||||||
import { Filter } from '../models/filter.model';
|
import { Filter } from '../models/filter.model';
|
||||||
import { filterMock } from 'mocks/filters.mock';
|
import { filterMock } from 'mocks/filters.mock';
|
||||||
import { CatSearchService, ApiResponse, UISettingsDTO } from 'cat-service';
|
import { CatSearchService, ApiResponse, UISettingsDTO } from 'cat-service';
|
||||||
import { expand } from 'rxjs/operators';
|
|
||||||
import { FilterItem } from '../models/filter-item.model';
|
import { FilterItem } from '../models/filter-item.model';
|
||||||
|
import { FilterMapping } from '../mappings/filter.mapping';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class FilterService {
|
export class FilterService {
|
||||||
constructor(private service: CatSearchService) {}
|
constructor(
|
||||||
|
private service: CatSearchService,
|
||||||
|
private filterMapping: FilterMapping
|
||||||
|
) { }
|
||||||
|
|
||||||
selectFilterById(filters: Filter[], id: string): Observable<Filter[]> {
|
selectFilterById(filters: Filter[], id: string): Observable<Filter[]> {
|
||||||
const newFilterState = filters.map((filter: Filter) => {
|
const newFilterState = filters.map((filter: Filter) => {
|
||||||
@@ -43,6 +47,17 @@ export class FilterService {
|
|||||||
return of(newFilterState);
|
return of(newFilterState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleFilterItemsByName(filters: Filter[], name: string): Observable<Filter[]> {
|
||||||
|
const newFilterState = filters.map((filter: Filter) => {
|
||||||
|
if (filter.expanded === true) {
|
||||||
|
const newItemsState = this.toggleItemByName(filter.items, name);
|
||||||
|
return { ...filter, items: newItemsState };
|
||||||
|
}
|
||||||
|
return { ...filter };
|
||||||
|
});
|
||||||
|
return of(newFilterState);
|
||||||
|
}
|
||||||
|
|
||||||
private toggleItem(items: FilterItem[], id: string): FilterItem[] {
|
private toggleItem(items: FilterItem[], id: string): FilterItem[] {
|
||||||
return items.map((item: FilterItem) => {
|
return items.map((item: FilterItem) => {
|
||||||
if (item.id === id) {
|
if (item.id === id) {
|
||||||
@@ -52,19 +67,30 @@ export class FilterService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toggleItemByName(items: FilterItem[], name: string): FilterItem[] {
|
||||||
|
return items.map((item: FilterItem) => {
|
||||||
|
if (item.name === name) {
|
||||||
|
return { ...item, selected: !item.selected };
|
||||||
|
}
|
||||||
|
return { ...item };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// service method to get the first 3 filters
|
// service method to get the first 3 filters
|
||||||
getFilters(): Observable<Filter[]> {
|
getFilters(): Observable<Filter[]> {
|
||||||
// TODO: implement call to backend API to get filter metadata
|
return this.service.settings().pipe(
|
||||||
// this.service.settings().subscribe(
|
map(
|
||||||
// (data: ApiResponse<UISettingsDTO>) =>
|
(data: ApiResponse<UISettingsDTO>) =>
|
||||||
// console.log(data.result.filter, data.result.orderBy, data)
|
this.filterMapping.fromUiSettingsDto(data.result).slice(0, 3)
|
||||||
// );
|
));
|
||||||
return of(filterMock.slice(0, 3));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// service method to get filters metadata
|
// service method to get filters metadata
|
||||||
getFullFilter(): Observable<Filter[]> {
|
getFullFilter(): Observable<Filter[]> {
|
||||||
// TODO: implement call to backend API to get filter metadata
|
return this.service.settings().pipe(
|
||||||
return of(filterMock);
|
map(
|
||||||
|
(data: ApiResponse<UISettingsDTO>) =>
|
||||||
|
this.filterMapping.fromUiSettingsDto(data.result)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
} from 'cat-service';
|
} from 'cat-service';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { Search } from '../models/search.model';
|
import { Search } from '../models/search.model';
|
||||||
|
import { FilterMapping } from '../mappings/filter.mapping';
|
||||||
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -22,7 +23,8 @@ export class ProductService {
|
|||||||
searchResponse$: Observable<PagedApiResponse<ItemDTO>>;
|
searchResponse$: Observable<PagedApiResponse<ItemDTO>>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private searchService: CatSearchService
|
private searchService: CatSearchService,
|
||||||
|
private filterMapping: FilterMapping
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
persistLastSearchToLocalStorage(param: string) {
|
persistLastSearchToLocalStorage(param: string) {
|
||||||
@@ -70,7 +72,8 @@ export class ProductService {
|
|||||||
take: search.take
|
take: search.take
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.searchService.search(queryToken).pipe(
|
const queryWithFilters = this.filterMapping.toQueryTokenDto(queryToken, search.fitlers);
|
||||||
|
return this.searchService.search(queryWithFilters).pipe(
|
||||||
map(response => {
|
map(response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const LOAD_FULL_FILTERS = '[FILTERS] Load full';
|
|||||||
export const SELECT_FILTER_BY_ID = '[FILTERS] Select by id';
|
export const SELECT_FILTER_BY_ID = '[FILTERS] Select by id';
|
||||||
export const UNSELECT_FILTER_BY_ID = '[FILTERS] Unselect by id';
|
export const UNSELECT_FILTER_BY_ID = '[FILTERS] Unselect by id';
|
||||||
export const TOGGLE_FILTER_ITEM_BY_ID = '[FILTERS] Toggle item by id';
|
export const TOGGLE_FILTER_ITEM_BY_ID = '[FILTERS] Toggle item by id';
|
||||||
|
export const TOGGLE_FILTER_ITEM_BY_NAME = '[FILTERS] Toggle item by name';
|
||||||
|
|
||||||
export class LoadFilters {
|
export class LoadFilters {
|
||||||
static readonly type = LOAD_FILTERS;
|
static readonly type = LOAD_FILTERS;
|
||||||
@@ -31,3 +32,9 @@ export class ToggleFilterItemById {
|
|||||||
|
|
||||||
constructor(public id: string, public payload: Filter[]) {}
|
constructor(public id: string, public payload: Filter[]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ToggleFilterItemByName {
|
||||||
|
static readonly type = TOGGLE_FILTER_ITEM_BY_NAME;
|
||||||
|
|
||||||
|
constructor(public name: string, public payload: Filter[]) {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { State, Selector, Action, StateContext } from '@ngxs/store';
|
|||||||
import { LoadFeed } from '../actions/feed.actions';
|
import { LoadFeed } from '../actions/feed.actions';
|
||||||
import { feedMock } from 'mocks/feed.mock';
|
import { feedMock } from 'mocks/feed.mock';
|
||||||
import { FeedCard } from '../../models/feed-card.model';
|
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 {
|
export class FeedStateModel {
|
||||||
feed: FeedCard[];
|
feed: FeedCard[];
|
||||||
@@ -16,7 +19,7 @@ export class FeedStateModel {
|
|||||||
})
|
})
|
||||||
export class FeedState {
|
export class FeedState {
|
||||||
|
|
||||||
constructor(private feedService: FeedService) {}
|
constructor(private feedService: FeedService, private feedMapping: FeedMapping) { }
|
||||||
|
|
||||||
@Selector()
|
@Selector()
|
||||||
static getFeed(state: FeedStateModel) {
|
static getFeed(state: FeedStateModel) {
|
||||||
@@ -26,13 +29,20 @@ export class FeedState {
|
|||||||
@Action(LoadFeed)
|
@Action(LoadFeed)
|
||||||
load(ctx: StateContext<FeedStateModel>) {
|
load(ctx: StateContext<FeedStateModel>) {
|
||||||
const state = ctx.getState();
|
const state = ctx.getState();
|
||||||
// TODO: implement api call to state
|
this.feedService.info().subscribe(
|
||||||
// this.feedService.info().subscribe(
|
(feed: PagedApiResponse<FeedDTO<any>>) => {
|
||||||
// (feed: any) => console.log(feed)
|
const feeds = feed.result.map(t =>
|
||||||
// );
|
this.feedMapping.fromFeedDTO(t)
|
||||||
ctx.patchState({
|
);
|
||||||
...state,
|
ctx.patchState({
|
||||||
feed: [...feedMock]
|
...state,
|
||||||
});
|
feed: [...feeds]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// ctx.patchState({
|
||||||
|
// ...state,
|
||||||
|
// feed: [...feedMock]
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import { Filter } from '../../models/filter.model';
|
import { Filter } from '../../models/filter.model';
|
||||||
import { State, Selector, Action, StateContext } from '@ngxs/store';
|
import { State, Selector, Action, StateContext } from '@ngxs/store';
|
||||||
import { LoadFilters, LoadFullFilters, SelectFilterById, UnselectFilterById, ToggleFilterItemById } from '../actions/filter.actions';
|
import {
|
||||||
|
LoadFilters,
|
||||||
|
LoadFullFilters,
|
||||||
|
SelectFilterById,
|
||||||
|
UnselectFilterById,
|
||||||
|
ToggleFilterItemById,
|
||||||
|
ToggleFilterItemByName
|
||||||
|
} from '../actions/filter.actions';
|
||||||
import { load } from '@angular/core/src/render3';
|
import { load } from '@angular/core/src/render3';
|
||||||
import { FilterService } from '../../services/filter.service';
|
import { FilterService } from '../../services/filter.service';
|
||||||
|
|
||||||
@@ -16,13 +23,18 @@ export class FilterStateModel {
|
|||||||
})
|
})
|
||||||
export class FilterState {
|
export class FilterState {
|
||||||
|
|
||||||
constructor(private filterService: FilterService) {}
|
constructor(private filterService: FilterService) { }
|
||||||
|
|
||||||
@Selector()
|
@Selector()
|
||||||
static getFilters(state: FilterStateModel) {
|
static getFilters(state: FilterStateModel) {
|
||||||
return state.filters;
|
return state.filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Selector()
|
||||||
|
static getSelectedFilters(state: FilterStateModel) {
|
||||||
|
return state.filters.filter(f => f.items.find(i => i.selected === true));
|
||||||
|
}
|
||||||
|
|
||||||
@Action(LoadFilters)
|
@Action(LoadFilters)
|
||||||
load(ctx: StateContext<FilterStateModel>) {
|
load(ctx: StateContext<FilterStateModel>) {
|
||||||
const state = ctx.getState();
|
const state = ctx.getState();
|
||||||
@@ -87,4 +99,17 @@ export class FilterState {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Action(ToggleFilterItemByName)
|
||||||
|
toggleItemByName(ctx: StateContext<FilterStateModel>, { name, payload }: ToggleFilterItemByName) {
|
||||||
|
const state = ctx.getState();
|
||||||
|
this.filterService.toggleFilterItemsByName(payload, name).subscribe(
|
||||||
|
(filters: Filter[]) => {
|
||||||
|
ctx.patchState({
|
||||||
|
...state,
|
||||||
|
filters: [...filters]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ProductService } from '../../services/product.service';
|
|||||||
import { RecentArticleSearch } from '../../models/recent-article-search.model';
|
import { RecentArticleSearch } from '../../models/recent-article-search.model';
|
||||||
import { GetProducts, LoadRecentProducts, AddSelectedProduct } from '../actions/product.actions';
|
import { GetProducts, LoadRecentProducts, AddSelectedProduct } from '../actions/product.actions';
|
||||||
import { ItemDTO } from 'dist/cat-service/lib/dtos';
|
import { ItemDTO } from 'dist/cat-service/lib/dtos';
|
||||||
import { getCurrentProcess } from '../../utils/process.util'
|
import { getCurrentProcess } from '../../utils/process.util';
|
||||||
|
|
||||||
export class ProcessStateModel {
|
export class ProcessStateModel {
|
||||||
processes: Process[];
|
processes: Process[];
|
||||||
@@ -202,7 +202,7 @@ export class ProcessState {
|
|||||||
(process: Process) => {
|
(process: Process) => {
|
||||||
if (process.selected === true) {
|
if (process.selected === true) {
|
||||||
if (removeLastBreadcrumb) {
|
if (removeLastBreadcrumb) {
|
||||||
let updateBreadcrumbs: Breadcrumb[] = [];
|
const updateBreadcrumbs: Breadcrumb[] = [];
|
||||||
process.breadcrumbs.forEach((breadcrumb: Breadcrumb, index: number) => {
|
process.breadcrumbs.forEach((breadcrumb: Breadcrumb, index: number) => {
|
||||||
if ((process.breadcrumbs.length - 1) !== index) {
|
if ((process.breadcrumbs.length - 1) !== index) {
|
||||||
updateBreadcrumbs.push(breadcrumb);
|
updateBreadcrumbs.push(breadcrumb);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Filter } from 'src/app/core/models/filter.model';
|
|||||||
import {
|
import {
|
||||||
SelectFilterById,
|
SelectFilterById,
|
||||||
UnselectFilterById,
|
UnselectFilterById,
|
||||||
ToggleFilterItemById
|
ToggleFilterItemByName
|
||||||
} from 'src/app/core/store/actions/filter.actions';
|
} from 'src/app/core/store/actions/filter.actions';
|
||||||
import { FilterItem } from 'src/app/core/models/filter-item.model';
|
import { FilterItem } from 'src/app/core/models/filter-item.model';
|
||||||
import { Store } from '@ngxs/store';
|
import { Store } from '@ngxs/store';
|
||||||
@@ -31,8 +31,9 @@ export class FilterItemComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectItem(item: FilterItem) {
|
selectItem(item: FilterItem) {
|
||||||
this.store.dispatch(new ToggleFilterItemById(item.id, this.filters));
|
this.store.dispatch(new ToggleFilterItemByName(item.name, this.filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto auto auto;
|
grid-template-columns: auto auto auto auto;
|
||||||
//grid-gap: 5vh;
|
//grid-gap: 5vh;
|
||||||
margin-top: 15px;
|
margin-top: 5px;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin-left: 15%;
|
margin-left: 15%;
|
||||||
line-height: 3;
|
line-height: 3;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Select, Store } from '@ngxs/store';
|
import { Select, Store } from '@ngxs/store';
|
||||||
|
import { FilterState } from 'src/app/core/store/state/filter.state';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-text-search',
|
selector: 'app-text-search',
|
||||||
@@ -41,6 +42,7 @@ export class TextSearchComponent implements OnInit, AfterViewInit {
|
|||||||
products: Product[];
|
products: Product[];
|
||||||
filters: Filter[];
|
filters: Filter[];
|
||||||
@Select(ProcessState.getProcesses) processes$: Observable<Process[]>;
|
@Select(ProcessState.getProcesses) processes$: Observable<Process[]>;
|
||||||
|
@Select(FilterState.getSelectedFilters) filters$: Observable<Filter[]>;
|
||||||
processes: Process[];
|
processes: Process[];
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@@ -62,7 +64,8 @@ export class TextSearchComponent implements OnInit, AfterViewInit {
|
|||||||
if (!this.searchParams) {
|
if (!this.searchParams) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.loadSelectedFilters();
|
this.filters$.subscribe(f => this.filters = f);
|
||||||
|
console.log(this.filters);
|
||||||
const search = <Search>{
|
const search = <Search>{
|
||||||
query: this.searchParams,
|
query: this.searchParams,
|
||||||
fitlers: this.filters,
|
fitlers: this.filters,
|
||||||
@@ -112,13 +115,6 @@ export class TextSearchComponent implements OnInit, AfterViewInit {
|
|||||||
.subscribe((data: any) => this.searchProductsHandler(data));
|
.subscribe((data: any) => this.searchProductsHandler(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSelectedFilters() {
|
|
||||||
// TODO filter selected filters
|
|
||||||
// this.store.select('filters').subscribe(
|
|
||||||
// (data: Filter[]) => this.filters = data
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
loadProcesses() {
|
loadProcesses() {
|
||||||
this.processes$.subscribe((data: Process[]) => (this.processes = data));
|
this.processes$.subscribe((data: Process[]) => (this.processes = data));
|
||||||
}
|
}
|
||||||
@@ -142,6 +138,7 @@ export class TextSearchComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createTab() {
|
createTab() {
|
||||||
|
this.searchParams = this.searchInput.input;
|
||||||
this.loadProcesses();
|
this.loadProcesses();
|
||||||
if (this.processes.length === 0) {
|
if (this.processes.length === 0) {
|
||||||
this.createProcess();
|
this.createProcess();
|
||||||
|
|||||||
@@ -2,38 +2,38 @@
|
|||||||
<div class="card-title align-left">
|
<div class="card-title align-left">
|
||||||
<span>{{card.cardTitle}}</span>
|
<span>{{card.cardTitle}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-items">
|
<div class="card-items" [ngClass]="{'single-item-mode': !card.books.secondBookAuthor}">
|
||||||
<div class="item align-left">
|
<div class="item align-left">
|
||||||
<div class="item-logo">
|
<div class="item-logo">
|
||||||
<img class="book-image" src="../../../assets/images/{{card.books.firstBookIcon}}">
|
<img class="book-image" [src]='firstBookImageUrl$ | async'>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-content">
|
<div class="item-content">
|
||||||
<div class="book-author wrap-text-more">{{card.books.firstBookAuthor}}</div>
|
<div class="book-author wrap-text-more">{{card.books.firstBookAuthor}}</div>
|
||||||
<div class="book-title wrap-text-more">{{card.books.firstBookTitle}}</div>
|
<div class="book-title wrap-text-more">{{card.books.firstBookTitle}}</div>
|
||||||
<div class="item-detail">
|
<div class="item-detail" [ngClass]="{'single-item-detail-mode': !card.books.secondBookAuthor}">
|
||||||
<div class="book-type">
|
<div class="book-type" [ngClass]="{'book-type-single-mode': !card.books.secondBookAuthor}">
|
||||||
<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.firstBookTypeIcon}}.svg"></div>
|
||||||
<div class="item-detail wrap-text-more">{{card.books.firstBookType}}</div>
|
<div class="item-detail wrap-text-more">{{card.books.firstBookType}}</div>
|
||||||
<div class="separator">|</div>
|
<div class="separator">|</div>
|
||||||
</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="item-details wrap-text-more">{{card.books.firstBookLanguage}}</div>
|
||||||
<div class="separator">|</div>
|
<div class="separator">|</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-details wrap-text-more">{{card.books.firstBookPrice}}</div>
|
<div class="item-details wrap-text-more">{{price}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item align-left">
|
<div class="item align-left" *ngIf="card.books.secondBookAuthor">
|
||||||
<div class="item-logo">
|
<div class="item-logo">
|
||||||
<img class="book-image" src="../../../assets/images/{{card.books.secondBookIcon}}">
|
<img class="book-image" [src]='secondBookImageUrl$ | async'>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-content">
|
<div class="item-content">
|
||||||
<div class="book-author wrap-text-more">{{card.books.secondBookAuthor}}</div>
|
<div class="book-author wrap-text-more">{{card.books.secondBookAuthor}}</div>
|
||||||
<div class="book-title wrap-text-more">{{card.books.secondBookTitle}}</div>
|
<div class="book-title wrap-text-more">{{card.books.secondBookTitle}}</div>
|
||||||
<div class="item-detail">
|
<div class="item-detail">
|
||||||
<div class="book-type">
|
<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="item-detail wrap-text-more">{{card.books.secondBookType}}</div>
|
||||||
<div class="separator">|</div>
|
<div class="separator">|</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<div class="item-details wrap-text-more">{{card.books.secondBookLanguage}}</div>
|
<div class="item-details wrap-text-more">{{card.books.secondBookLanguage}}</div>
|
||||||
<div class="separator">|</div>
|
<div class="separator">|</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-details wrap-text-more">{{card.books.secondBookPrice}}</div>
|
<div class="item-details wrap-text-more">{{secondPrice}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.single-item-mode {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 563px) {
|
@media screen and (max-width: 563px) {
|
||||||
.card-items {
|
.card-items {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -53,6 +57,11 @@
|
|||||||
grid-template-columns: auto auto auto;
|
grid-template-columns: auto auto auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.single-item-detail-mode {
|
||||||
|
grid-template-columns: max-content max-content auto;
|
||||||
|
grid-gap: 2vh;
|
||||||
|
}
|
||||||
|
|
||||||
.book-author {
|
.book-author {
|
||||||
height: 21px;
|
height: 21px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -70,6 +79,10 @@
|
|||||||
grid-template-columns: auto auto auto;
|
grid-template-columns: auto auto auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.book-type-single-mode {
|
||||||
|
grid-gap: 1vh;
|
||||||
|
}
|
||||||
|
|
||||||
.separator .item-details {
|
.separator .item-details {
|
||||||
height: 21px;
|
height: 21px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -80,3 +93,11 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto;
|
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 { Component, OnInit, Input } from '@angular/core';
|
||||||
import { FeedCard } from 'src/app/core/models/feed-card.model';
|
import { FeedCard } from 'src/app/core/models/feed-card.model';
|
||||||
|
import { CatImageService } from 'cat-service';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-book-card',
|
selector: 'app-book-card',
|
||||||
@@ -9,10 +11,34 @@ import { FeedCard } from 'src/app/core/models/feed-card.model';
|
|||||||
export class BookCardComponent implements OnInit {
|
export class BookCardComponent implements OnInit {
|
||||||
|
|
||||||
@Input() card: FeedCard;
|
@Input() card: FeedCard;
|
||||||
|
firstBookImageUrl$: Observable<string>;
|
||||||
|
secondBookImageUrl$: Observable<string>;
|
||||||
|
|
||||||
constructor() { }
|
constructor(private catImageService: CatImageService) { }
|
||||||
|
|
||||||
|
get price() {
|
||||||
|
if (this.card.books.firstBookPrice.toString().indexOf('.') === -1) {
|
||||||
|
return this.card.books.firstBookPrice + ',00 ' + this.card.books.firstBookCurrency;
|
||||||
|
}
|
||||||
|
return this.card.books.firstBookPrice.replace('.', ',') + ' ' + this.card.books.firstBookCurrency;
|
||||||
|
}
|
||||||
|
|
||||||
|
get secondPrice() {
|
||||||
|
if (this.card.books.secondBookPrice.toString().indexOf('.') === -1) {
|
||||||
|
return this.card.books.secondBookPrice + ',00 ' + this.card.books.secondBookPrice;
|
||||||
|
}
|
||||||
|
return this.card.books.secondBookPrice.replace('.', ',') + ' ' + this.card.books.secondBookPrice;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
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">
|
<div class="card-title align-left">
|
||||||
<span>{{card.cardTitle}}</span>
|
<span>{{card.cardTitle}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="event-title align-left wrap-text-more">
|
<div class="event-title align-left wrap-text-more">
|
||||||
<span>{{card.event.title}}</span>
|
<span [innerHTML]='event.title'></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="event-content align-left">
|
<div class="event-content align-left">
|
||||||
<span>{{card.event.content}}</span>
|
<span [innerHTML]='event.content'></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
<div class="card-container">
|
<div class="card-container card-container-no-image" *ngFor="let news of card.news">
|
||||||
<div class="card-icon-container align-center">
|
<!-- <div class="card-icon-container align-center">
|
||||||
<img class="news-icon" src="../../../assets/images/News_Icon.svg">
|
<img class="news-icon" src="../../../assets/images/News_Icon.svg">
|
||||||
</div>
|
</div> -->
|
||||||
<div class="card-content-container">
|
<div class="card-content-container">
|
||||||
<div class="card-title align-left">
|
<div class="card-title align-left">
|
||||||
<span>{{card.cardTitle}}</span>
|
<span>{{card.cardTitle}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="news-title align-left wrap-text-more">
|
<div class="news-title align-left wrap-text-more">
|
||||||
<span>{{card.news.title}}</span>
|
<span>{{news.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="news-content align-left">
|
<div class="news-content align-left">
|
||||||
<span>{{card.news.content}}</span>
|
<span>{{news.content}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -13,6 +13,10 @@
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-container-no-image {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.card-content-container {
|
.card-content-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto;
|
grid-template-columns: auto;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<div *ngFor="let card of feed$ | async">
|
<div *ngFor="let card of feed$ | async">
|
||||||
<app-book-card *ngIf="card.type === 'BOOK'" [card]="card"></app-book-card>
|
<app-book-card *ngIf="card.type === 'products'" [card]="card"></app-book-card>
|
||||||
<app-event-card *ngIf="card.type === 'EVENT'" [card]="card"></app-event-card>
|
<app-event-card *ngIf="card.type === 'events'" [card]="card"></app-event-card>
|
||||||
<app-news-card *ngIf="card.type === 'NEWS'" [card]="card"></app-news-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>
|
<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 {
|
export class DashboardComponent implements OnInit {
|
||||||
|
|
||||||
|
loading = true;
|
||||||
|
|
||||||
@Select(FeedState.getFeed) feed$: Observable<FeedCard[]>;
|
@Select(FeedState.getFeed) feed$: Observable<FeedCard[]>;
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store
|
private store: Store
|
||||||
@@ -19,5 +21,8 @@ export class DashboardComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.store.dispatch(new LoadFeed());
|
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 { EventCardComponent } from './components/event-card/event-card.component';
|
||||||
import { NewsCardComponent } from './components/news-card/news-card.component';
|
import { NewsCardComponent } from './components/news-card/news-card.component';
|
||||||
import { RecommandationCardComponent } from './components/recommandation-card/recommandation-card.component';
|
import { RecommandationCardComponent } from './components/recommandation-card/recommandation-card.component';
|
||||||
|
import { SharedModule } from 'src/app/shared/shared.module';
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule],
|
imports: [CommonModule, SharedModule],
|
||||||
exports: [DashboardComponent],
|
exports: [DashboardComponent],
|
||||||
declarations: [
|
declarations: [
|
||||||
DashboardComponent,
|
DashboardComponent,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
/* semi-transparent black */
|
/* semi-transparent black */
|
||||||
background-color: #000;
|
background-color: #1B1E32;
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
|
||||||
/* z-index must be below .jw-modal and above everything else */
|
/* z-index must be below .jw-modal and above everything else */
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
src="/assets/images/close.svg"
|
src="/assets/images/close.svg"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
(click)="search.emit(input)"
|
(click)="emitSearch(input)"
|
||||||
class="search-icon"
|
class="search-icon"
|
||||||
src="/assets/images/search.svg"
|
src="/assets/images/search.svg"
|
||||||
/>
|
/>
|
||||||
@@ -62,6 +62,10 @@ export class SearchComponent implements OnInit {
|
|||||||
this.change('');
|
this.change('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitSearch(input: string) {
|
||||||
|
this.search.emit(input);
|
||||||
|
}
|
||||||
|
|
||||||
keyHandler(event: any) {
|
keyHandler(event: any) {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
this.search.emit(this.input);
|
this.search.emit(this.input);
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700" rel="stylesheet">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
|
|||||||
Reference in New Issue
Block a user