-
Notifications
You must be signed in to change notification settings - Fork 8
feat(main): newsletter & top banners #380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5a7f82f
87d4b61
db7cc3d
fd83adb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,46 @@ | ||
import { Slider } from '@angular-love/blog/contracts/banners'; | ||
import { Banners } from '@angular-love/blog/contracts/banners'; | ||
|
||
import { WPBannerDto, WPBannerMediaDto } from './dtos'; | ||
|
||
export const toBanner = ( | ||
dto: WPBannerDto, | ||
mediaDto: WPBannerMediaDto[], | ||
): Slider => { | ||
): Banners => { | ||
return { | ||
slideDisplayTimeMs: +dto.acf.display_time, | ||
slides: | ||
dto.acf.slides?.map((slide) => { | ||
const media = mediaDto.find((media) => media.id === slide.slide_image)!; | ||
return { | ||
url: media.guid.rendered, | ||
alt: media.alt_text, | ||
navigateTo: slide.slide_url, | ||
}; | ||
}) ?? [], | ||
...(dto.acf.is_slider_banner_displayed && { | ||
slider: { | ||
slideDisplayTimeMs: +dto.acf.display_time, | ||
slides: dto.acf.slides.map((slide) => { | ||
const media = mediaDto.find( | ||
(media) => media.id === slide.slide_image_desktop, | ||
)!; | ||
return { | ||
url: media?.guid.rendered, | ||
alt: media?.alt_text, | ||
navigateTo: slide.slide_url, | ||
}; | ||
}), | ||
}, | ||
}), | ||
...(dto.acf.is_top_banner_displayed && { | ||
topBanner: { | ||
url: mediaDto.find( | ||
(media) => media.id === dto.acf.top_banner_image_desktop, | ||
)?.guid.rendered, | ||
alt: mediaDto.find( | ||
(media) => media.id === dto.acf.top_banner_image_desktop, | ||
)?.alt_text, | ||
navigateTo: dto.acf.top_banner_image_url, | ||
}, | ||
}), | ||
...(dto.acf.is_card_banner_displayed && { | ||
cardBanner: { | ||
url: mediaDto.find((media) => media.id === dto.acf.card_banner_image) | ||
?.guid.rendered, | ||
alt: mediaDto.find((media) => media.id === dto.acf.card_banner_image) | ||
?.alt_text, | ||
navigateTo: dto.acf.card_banner_url, | ||
}, | ||
}), | ||
}; | ||
Comment on lines
+25
to
45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Code duplication in media lookups There's significant duplication in the media lookup logic across all banner types, and mobile images aren't being used. Consider extracting the media lookup logic into a helper function and using mobile images for responsive design: export const toBanner = (
dto: WPBannerDto,
mediaDto: WPBannerMediaDto[],
): Banners => {
+ const findMedia = (mediaId: number) => mediaDto.find(media => media.id === mediaId);
+
return {
...(dto.acf.is_slider_banner_displayed && {
slider: {
slideDisplayTimeMs: +dto.acf.display_time,
slides: dto.acf.slides.map((slide) => {
- const media = mediaDto.find(
- (media) => media.id === slide.slide_image_desktop,
- )!;
+ const desktopMedia = findMedia(slide.slide_image_desktop);
+ const mobileMedia = findMedia(slide.slide_image_mobile);
return {
- url: media?.guid.rendered,
- alt: media?.alt_text,
+ url: desktopMedia?.guid.rendered,
+ mobileUrl: mobileMedia?.guid.rendered,
+ alt: desktopMedia?.alt_text,
navigateTo: slide.slide_url,
};
}),
},
}),
...(dto.acf.is_top_banner_displayed && {
topBanner: {
- url: mediaDto.find(
- (media) => media.id === dto.acf.top_banner_image_desktop,
- )?.guid.rendered,
- alt: mediaDto.find(
- (media) => media.id === dto.acf.top_banner_image_desktop,
- )?.alt_text,
+ url: findMedia(dto.acf.top_banner_image_desktop)?.guid.rendered,
+ mobileUrl: findMedia(dto.acf.top_banner_image_mobile)?.guid.rendered,
+ alt: findMedia(dto.acf.top_banner_image_desktop)?.alt_text,
navigateTo: dto.acf.top_banner_image_url,
},
}),
...(dto.acf.is_card_banner_displayed && {
cardBanner: {
- url: mediaDto.find((media) => media.id === dto.acf.card_banner_image)
- ?.guid.rendered,
- alt: mediaDto.find((media) => media.id === dto.acf.card_banner_image)
- ?.alt_text,
+ url: findMedia(dto.acf.card_banner_image)?.guid.rendered,
+ alt: findMedia(dto.acf.card_banner_image)?.alt_text,
navigateTo: dto.acf.card_banner_url,
},
}),
};
}; Note: You would need to update the banner interfaces to include |
||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,27 @@ | ||
export interface Slider { | ||
slideDisplayTimeMs: number; | ||
slides: { | ||
url: string; | ||
alt: string; | ||
url?: string; | ||
alt?: string; | ||
navigateTo: string; | ||
}[]; | ||
} | ||
|
||
export interface TopBanner { | ||
navigateTo?: string; | ||
buttonText?: string; | ||
text: string; | ||
buttonPosition: 'left' | 'right'; | ||
} | ||
|
||
export interface CardBanner { | ||
url?: string; | ||
alt?: string; | ||
navigateTo: string; | ||
} | ||
|
||
export interface Banners { | ||
slider?: Slider; | ||
topBanner?: TopBanner; | ||
cardBanner?: CardBanner; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,15 @@ | ||
import { HttpClient } from '@angular/common/http'; | ||
import { inject, Injectable } from '@angular/core'; | ||
import { map } from 'rxjs'; | ||
|
||
import { Slider } from '@angular-love/blog/contracts/banners'; | ||
import { Banners } from '@angular-love/blog/contracts/banners'; | ||
import { ConfigService } from '@angular-love/shared/config'; | ||
|
||
@Injectable({ providedIn: 'root' }) | ||
export class AdBannerService { | ||
private readonly _apiBaseUrl = inject(ConfigService).get('apiBaseUrl'); | ||
private readonly _http = inject(HttpClient); | ||
|
||
getBannerSlider() { | ||
return this._http | ||
.get<{ banners: Slider }>(`./assets/banners.json`) | ||
.pipe(map((resp) => resp.banners)); | ||
getVisibleBanners() { | ||
return this._http.get<Banners>(`${this._apiBaseUrl}/banners`); | ||
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainConsider caching mechanism to address previous concerns about redundant requests. The method has been appropriately renamed from However, I noticed in past review comments a concern about making redundant banner requests during prerendering. Consider implementing a caching mechanism or moving to a static JSON asset as previously suggested to optimize performance. 🏁 Script executed: #!/bin/bash
# Check if there's any caching implementation for banner requests
echo "Searching for caching implementations in banner-related code..."
rg -A 5 -B 5 "cache|shareReplay|replaySubject" --iglob "**/*banner*/**" Length of output: 1094 🌐 Web query:
💡 Result: During Angular SSR (Server-Side Rendering) or prerendering, it's common to face redundant API requests because Angular's rendering lifecycle might trigger multiple calls to the same data source. Here are some common strategies to reduce these redundant requests:
Summary: The most effective and widely used approach is combining Angular's Implement HTTP caching to prevent redundant banner requests during SSR This service currently issues a fresh HTTP GET on every call:
To optimize performance during Angular Universal prerendering, consider one or more of the following: • Use Angular’s TransferState API See Angular’s TransferState guide for details: https://angular.io/api/platform-browser/TransferState |
||
} | ||
Comment on lines
+12
to
14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we host this data as a json asset? it would be created in the build time as a part of the process in With current implementation we fetch banners from BFF for every available page. Basically it adds an extra request during prerendering. If we prerender 500 pages, it ends up with BFF 1000 request, where 50% is the same banners request. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure, we can do that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this pr resolves the issue #415 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export * from './lib/ad-image-banner/ad-image-banner.component'; | ||
export * from './lib/ad-image-banner/ad-image-banner-data.interface'; | ||
export * from './lib/ad-image-banner/ad-image-banner.component'; | ||
export * from './lib/banner-carousel/al-banner-carousel.component'; | ||
export * from './lib/newsletter-banner/al-newsletter-banner.component'; | ||
export * from './lib/top-banner.component'; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,44 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { NgOptimizedImage } from '@angular/common'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ChangeDetectionStrategy, Component, input } from '@angular/core'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { CardBanner } from '@angular-love/blog/contracts/banners'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Component({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
selector: 'al-newsletter-banner', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
imports: [NgOptimizedImage], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
changeDetection: ChangeDetectionStrategy.OnPush, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
template: ` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class="relative flex h-full items-center justify-center" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[href]="cardBanner().navigateTo!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<aside class="absolute h-full w-full overflow-hidden rounded-lg"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<img | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tabindex="0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
role="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class="!relative object-cover shadow-inner blur-xl" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[attr.aria-label]="cardBanner()!.alt!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[alt]="cardBanner().alt!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[ngSrc]="cardBanner().url!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fill | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
priority | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</aside> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<aside> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<img | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tabindex="0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
role="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class="!relative" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[attr.aria-label]="cardBanner().alt!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[alt]="cardBanner().alt!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[ngSrc]="cardBanner().url!" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fill | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
priority | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</aside> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</a> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+10
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve template safety and accessibility. The template has several issues that should be addressed:
Consider this safer and more efficient approach: - template: `
- <a
- class="relative flex h-full items-center justify-center"
- [href]="cardBanner().navigateTo!"
- >
- <aside class="absolute h-full w-full overflow-hidden rounded-lg">
- <img
- tabindex="0"
- role="button"
- class="!relative object-cover shadow-inner blur-xl"
- [attr.aria-label]="cardBanner()!.alt!"
- [alt]="cardBanner().alt!"
- [ngSrc]="cardBanner().url!"
- fill
- priority
- />
- </aside>
- <aside>
- <img
- tabindex="0"
- role="button"
- class="!relative"
- [attr.aria-label]="cardBanner().alt!"
- [alt]="cardBanner().alt!"
- [ngSrc]="cardBanner().url!"
- fill
- priority
- />
- </aside>
- </a>
+ template: `
+ <a
+ class="relative flex h-full items-center justify-center"
+ [href]="cardBanner().navigateTo"
+ >
+ <aside class="absolute h-full w-full overflow-hidden rounded-lg">
+ <img
+ *ngIf="cardBanner().url"
+ class="!relative object-cover shadow-inner blur-xl"
+ [attr.aria-label]="cardBanner().alt || 'Newsletter banner'"
+ [alt]="cardBanner().alt || 'Newsletter banner'"
+ [ngSrc]="cardBanner().url"
+ fill
+ priority
+ />
+ </aside>
+ <aside>
+ <img
+ *ngIf="cardBanner().url"
+ class="!relative"
+ [attr.aria-label]="cardBanner().alt || 'Newsletter banner'"
+ [alt]="cardBanner().alt || 'Newsletter banner'"
+ [ngSrc]="cardBanner().url"
+ fill
+ priority
+ />
+ </aside>
+ </a> Alternatively, consider using CSS for the blurred background effect instead of loading the same image twice: - template: `
- <a
- class="relative flex h-full items-center justify-center"
- [href]="cardBanner().navigateTo!"
- >
- <aside class="absolute h-full w-full overflow-hidden rounded-lg">
- <img
- tabindex="0"
- role="button"
- class="!relative object-cover shadow-inner blur-xl"
- [attr.aria-label]="cardBanner()!.alt!"
- [alt]="cardBanner().alt!"
- [ngSrc]="cardBanner().url!"
- fill
- priority
- />
- </aside>
- <aside>
- <img
- tabindex="0"
- role="button"
- class="!relative"
- [attr.aria-label]="cardBanner().alt!"
- [alt]="cardBanner().alt!"
- [ngSrc]="cardBanner().url!"
- fill
- priority
- />
- </aside>
- </a>
+ template: `
+ <a
+ class="relative flex h-full items-center justify-center"
+ [href]="cardBanner().navigateTo"
+ >
+ <div *ngIf="cardBanner().url" class="banner-container">
+ <img
+ class="banner-image"
+ [attr.aria-label]="cardBanner().alt || 'Newsletter banner'"
+ [alt]="cardBanner().alt || 'Newsletter banner'"
+ [ngSrc]="cardBanner().url"
+ fill
+ priority
+ />
+ </div>
+ </a>
+ `,
+ styles: [`
+ .banner-container {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ border-radius: 0.5rem;
+ }
+ .banner-container::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-image: inherit;
+ background-size: cover;
+ filter: blur(16px);
+ z-index: 0;
+ }
+ .banner-image {
+ position: relative;
+ z-index: 1;
+ }
+ `] 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export class AlNewsletterBannerComponent { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
readonly cardBanner = input.required<CardBanner>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -9,15 +9,18 @@ import { | |||||||||||||||||||||||||||||||||||||
import { RouterLink } from '@angular/router'; | ||||||||||||||||||||||||||||||||||||||
import { TranslocoDirective } from '@jsverse/transloco'; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
import { AdBannerStore } from '@angular-love/blog/ad-banner/data-access'; | ||||||||||||||||||||||||||||||||||||||
import { ArticleListStore } from '@angular-love/blog/articles/data-access'; | ||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||
ArticleRegularCardSkeletonComponent, | ||||||||||||||||||||||||||||||||||||||
UiArticleCardComponent, | ||||||||||||||||||||||||||||||||||||||
} from '@angular-love/blog/articles/ui-article-card'; | ||||||||||||||||||||||||||||||||||||||
import { NewsletterComponent } from '@angular-love/blog/newsletter'; | ||||||||||||||||||||||||||||||||||||||
import { AlNewsletterBannerComponent } from '@angular-love/blog/shared/ad-banner'; | ||||||||||||||||||||||||||||||||||||||
import { ButtonComponent } from '@angular-love/blog/shared/ui-button'; | ||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||
CardComponent, | ||||||||||||||||||||||||||||||||||||||
CardContentDirective, | ||||||||||||||||||||||||||||||||||||||
GradientCardDirective, | ||||||||||||||||||||||||||||||||||||||
} from '@angular-love/blog/shared/ui-card'; | ||||||||||||||||||||||||||||||||||||||
import { PillDirective } from '@angular-love/blog/shared/ui-pill'; | ||||||||||||||||||||||||||||||||||||||
|
@@ -34,15 +37,16 @@ import { CategoryListItem, injectCategories } from './categories.const'; | |||||||||||||||||||||||||||||||||||||
UiArticleCardComponent, | ||||||||||||||||||||||||||||||||||||||
NewsletterComponent, | ||||||||||||||||||||||||||||||||||||||
CardComponent, | ||||||||||||||||||||||||||||||||||||||
GradientCardDirective, | ||||||||||||||||||||||||||||||||||||||
NgClass, | ||||||||||||||||||||||||||||||||||||||
TranslocoDirective, | ||||||||||||||||||||||||||||||||||||||
ArticleRegularCardSkeletonComponent, | ||||||||||||||||||||||||||||||||||||||
CardComponent, | ||||||||||||||||||||||||||||||||||||||
RepeatDirective, | ||||||||||||||||||||||||||||||||||||||
CardContentDirective, | ||||||||||||||||||||||||||||||||||||||
AlNewsletterBannerComponent, | ||||||||||||||||||||||||||||||||||||||
RouterLink, | ||||||||||||||||||||||||||||||||||||||
ButtonComponent, | ||||||||||||||||||||||||||||||||||||||
PillDirective, | ||||||||||||||||||||||||||||||||||||||
GradientCardDirective, | ||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||
host: { | ||||||||||||||||||||||||||||||||||||||
'data-testid': 'latest-articles-container', | ||||||||||||||||||||||||||||||||||||||
|
@@ -61,13 +65,19 @@ export class FeatureLatestArticlesComponent { | |||||||||||||||||||||||||||||||||||||
readonly take = 8; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
private readonly _articleListStore = inject(ArticleListStore); | ||||||||||||||||||||||||||||||||||||||
private readonly _bannerStore = inject(AdBannerStore); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// todo: remove this once the card banner is implemented | ||||||||||||||||||||||||||||||||||||||
protected readonly cardBanner = computed(() => { | ||||||||||||||||||||||||||||||||||||||
this._bannerStore.banners(); | ||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||
url: 'https://img.freepik.com/free-psd/banner-template-black-friday-clearance_23-2148745448.jpg', | ||||||||||||||||||||||||||||||||||||||
alt: 'Card Banner Example', | ||||||||||||||||||||||||||||||||||||||
navigateTo: '/', | ||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+70
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Temporary banner implementation needs improvement The current implementation calls Consider one of these alternatives: - // todo: remove this once the card banner is implemented
- protected readonly cardBanner = computed(() => {
- this._bannerStore.banners();
- return {
- url: 'https://img.freepik.com/free-psd/banner-template-black-friday-clearance_23-2148745448.jpg',
- alt: 'Card Banner Example',
- navigateTo: '/',
- };
- });
+ // todo: remove this hardcoded fallback once the card banner is fully implemented
+ protected readonly cardBanner = computed(() => {
+ const banners = this._bannerStore.banners();
+ return banners?.cardBanner || {
+ url: 'https://img.freepik.com/free-psd/banner-template-black-friday-clearance_23-2148745448.jpg',
+ alt: 'Card Banner Example',
+ navigateTo: '/',
+ };
+ }); Or if you want to keep it truly hardcoded for now: - // todo: remove this once the card banner is implemented
- protected readonly cardBanner = computed(() => {
- this._bannerStore.banners();
- return {
- url: 'https://img.freepik.com/free-psd/banner-template-black-friday-clearance_23-2148745448.jpg',
- alt: 'Card Banner Example',
- navigateTo: '/',
- };
- });
+ // todo: replace with real banner implementation
+ protected readonly cardBanner = computed(() => ({
+ url: 'https://img.freepik.com/free-psd/banner-template-black-friday-clearance_23-2148745448.jpg',
+ alt: 'Card Banner Example',
+ navigateTo: '/',
+ })); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||
readonly isFetchArticleListLoading = | ||||||||||||||||||||||||||||||||||||||
this._articleListStore.isFetchArticleListLoading; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
readonly isFetchArticleListError = | ||||||||||||||||||||||||||||||||||||||
this._articleListStore.isFetchArticleListError; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
readonly articles = this._articleListStore.articles; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
constructor() { | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Card banner missing mobile image support
Unlike slider and top banner, the card banner only has a single image property without device-specific versions.
Is this intentional, or should card banners also support device-specific images like the other banner types?
🏁 Script executed:
Length of output: 1306
I’d like to inspect the banner DTO definitions to confirm which types include device-specific images. Let me pull out the related sections for slider, mobile, and desktop in
dtos.ts
:🏁 Script executed:
Length of output: 1786
Ensure Device-Specific Images for Card Banners
The
card_banner
DTO currently only exposes a singlecard_banner_image
, whereas both the slider and top banners define separate desktop and mobile image fields. To maintain consistency and support mobile layouts, please split the card banner image into desktop and mobile variants (or confirm and document that a single image is intentional).• In
libs/blog-bff/banners/api/src/lib/dtos.ts
Replace:
With:
• In
libs/blog-bff/banners/api/src/lib/mappers.ts
Update the
cardBanner
mapping to source both URLs:If the single-image design is intentional, please add a comment in the DTO or README explaining why card banners differ.