Skip to content

Commit

Permalink
fix(announcements): menu item mark as read (#27548)
Browse files Browse the repository at this point in the history
* #27494 Implement mark as read

* #27494 Adding announcement test has been read test

* removing space

* Fix test
  • Loading branch information
manuelrojas authored Feb 8, 2024
1 parent a394d57 commit 181a067
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ <h5 class="announcements__title">{{ 'announcements' | dm }}</h5>
@for (item of announcements(); track item.identifier;) {
<li
class="announcements__list-item"
[class.announcements__list-item--active]="showUnreadAnnouncement">
<span class="announcements__badge" *ngIf="showUnreadAnnouncement"></span>
[class.announcements__list-item--active]="!item.hasBeenRead">
<span class="announcements__badge" *ngIf="!item.hasBeenRead"></span>
<span class="announcements__image pi" [ngClass]="typesIcons[item.type]"></span>
<a
class="announcements__url"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NgClass, NgForOf, CommonModule } from '@angular/common';
import { Component, Input, OnInit, Signal, inject } from '@angular/core';
import { Component, Input, OnChanges, OnInit, Signal, inject } from '@angular/core';
import { RouterLink } from '@angular/router';

import { skip } from 'rxjs/operators';
Expand All @@ -22,7 +22,7 @@ import { DotMessagePipe } from '@dotcms/ui';
imports: [NgForOf, NgClass, DotMessagePipe, RouterLink, CommonModule],
providers: [AnnouncementsStore]
})
export class DotToolbarAnnouncementsComponent implements OnInit {
export class DotToolbarAnnouncementsComponent implements OnInit, OnChanges {
announcementsStore = inject(AnnouncementsStore);
dotMessageService = inject(DotMessageService);
siteService = inject(SiteService);
Expand All @@ -43,6 +43,10 @@ export class DotToolbarAnnouncementsComponent implements OnInit {
});
}

ngOnChanges(): void {
this.announcementsStore.markAnnouncementsAsRead();
}

typesIcons = {
tip: TypesIcons.Tip,
release: TypesIcons.Release,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ describe('AnnouncementsStore', () => {
announcementDateAsISO8601: '2024-01-31T17:51',
identifier: 'test-announcement-id',
inode: '123',
url: 'https://www.example.com'
url: 'https://www.example.com',
hasBeenRead: false
}
]
})
Expand All @@ -44,19 +45,22 @@ describe('AnnouncementsStore', () => {
});

it('should fetch announcements', (done) => {
localStorage.removeItem('dotAnnouncementsData');
const mockAnnouncements: Announcement[] = [
{
title: 'Test Announcement',
type: 'announcement',
announcementDateAsISO8601: '2024-01-31T17:51',
identifier: 'test-announcement-id',
inode: '123',
hasBeenRead: false,
url: 'https://www.example.com?utm_source=platform&utm_medium=announcement&utm_campaign=demo.dotcms.com'
}
];
spectator.service.load();
spectator.service.state$.subscribe((state) => {
expect(state.announcements).toEqual(mockAnnouncements);
expect(state.announcements[0].hasBeenRead).toBe(false);
done();
});
});
Expand All @@ -68,6 +72,7 @@ describe('AnnouncementsStore', () => {

spectator.service.state$.subscribe((state) => {
expect(state.showUnreadAnnouncement).toBe(false);
expect(state.announcements[0].hasBeenRead).toBe(true);
done();
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type Announcement = {
identifier: string;
inode: string;
url: string;
hasBeenRead: boolean;
};

export type AnnouncementLink = {
Expand Down Expand Up @@ -60,7 +61,7 @@ export class AnnouncementsStore extends ComponentStore<DotAnnouncementsState> {
return this.http.get<Announcement[]>(this.announcementsUrl).pipe(
pluck('entity'),
tap((announcements: Announcement[]) => {
const modifiedAnnouncements = this.appendUtmParameters(announcements);
const modifiedAnnouncements = this.updateWithUtmAndReadStatus(announcements);

this.setState({
announcements: modifiedAnnouncements,
Expand Down Expand Up @@ -138,16 +139,23 @@ export class AnnouncementsStore extends ComponentStore<DotAnnouncementsState> {
readonly selectLinkToDotCms: Signal<string> = this.selectSignal((state) => {
return `https://www.dotcms.com/announcement-menu-show-all?${state.utmParameters}`;
});

/**
* Mark announcements as read, validating it doesn't have any announcements
*
* @memberof AnnouncementsStore
*/
readonly markAnnouncementsAsRead = this.updater((state) => {
this.localStoreService.storeValue(
'dotAnnouncementsData',
JSON.stringify(state.announcements)
);
if (state.announcements.length !== 0) {
this.localStoreService.storeValue(
'dotAnnouncementsData',
JSON.stringify(state.announcements.map((announcement) => announcement.inode))
);
}

return {
...state,
showUnreadAnnouncement: this.hasUnreadAnnouncements(state.announcements)
showUnreadAnnouncement: this.hasUnreadAnnouncements(state.announcements),
announcements: this.updateWithUtmAndReadStatus(state.announcements)
};
});

Expand All @@ -162,29 +170,34 @@ export class AnnouncementsStore extends ComponentStore<DotAnnouncementsState> {
return `utm_source=platform&utm_medium=announcement&utm_campaign=${this.siteService.currentSite.hostname}`;
}

private appendUtmParameters(announcements: Announcement[]): Announcement[] {
private updateWithUtmAndReadStatus(announcements: Announcement[]): Announcement[] {
const storedAnnouncements = this.getStoredAnnouncements();

const modifiedAnnouncements = announcements.map((announcement) => {
return {
...announcement,
url: `${announcement.url}?${this.generateUtmQueryString()}`
url: `${announcement.url}?${this.generateUtmQueryString()}`,
hasBeenRead: storedAnnouncements.includes(announcement.inode)
};
});

return modifiedAnnouncements;
}

private hasUnreadAnnouncements(announcements: Announcement[]): boolean {
private getStoredAnnouncements(): string[] {
const storedAnnouncementsJson = this.localStoreService.getValue('dotAnnouncementsData');
const storedAnnouncements: Announcement[] = storedAnnouncementsJson
? JSON.parse(storedAnnouncementsJson)
: [];

return storedAnnouncementsJson ? JSON.parse(storedAnnouncementsJson) : [];
}

private hasUnreadAnnouncements(announcements: Announcement[]): boolean {
const storedAnnouncements: string[] = this.getStoredAnnouncements();

const newAnnouncements = announcements || [];
const newAnnouncementIds = newAnnouncements.map((announcement) => announcement.inode);
const storedAnnouncementIds = storedAnnouncements.map((announcement) => announcement.inode);

const isNewAnnouncement = newAnnouncementIds.some(
(id) => !storedAnnouncementIds.includes(id)
(id) => !storedAnnouncements.includes(id)
);

return isNewAnnouncement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2972,7 +2972,7 @@ announcements.contact.professional.services=Professional Services
announcements.contact.request.feature=Request a Feature
announcements.contact.report.bug=Report a Bug
announcements.knowledge.center.documentation=Documentation
announcements.knowledge.center.blog=Blog
announcements.knowledge.center.blog=dotCMS Blog
announcements.knowledge.center.github=GitHub Repository
announcements.knowledge.center.training=Online Training
announcements.knowledge.center.forum=Forum
Expand Down

0 comments on commit 181a067

Please sign in to comment.