Skip to content

Commit 85f7fbd

Browse files
authored
Merge pull request #700 from GetStream/blocked-message-component
feat: display message blocked component when message is blocked by mo…
2 parents 39bdfaf + f0f9b00 commit 85f7fbd

16 files changed

+868
-587
lines changed

package-lock.json

Lines changed: 43 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
"@ctrl/ngx-emoji-mart": "^8.2.0",
118118
"@floating-ui/dom": "^1.6.3",
119119
"@ngx-translate/core": "^14.0.0",
120-
"@stream-io/stream-chat-css": "5.6.1",
120+
"@stream-io/stream-chat-css": "5.8.0",
121121
"@stream-io/transliterate": "^1.5.2",
122122
"angular-mentions": "1.4.0",
123123
"dayjs": "^1.11.10",
@@ -128,7 +128,7 @@
128128
"pretty-bytes": "^6.1.1",
129129
"rxjs": "~7.4.0",
130130
"starwars-names": "^1.6.0",
131-
"stream-chat": "^8.44.0",
131+
"stream-chat": "^8.60.0",
132132
"ts-node": "^10.9.2",
133133
"tslib": "^2.3.0",
134134
"uuid": "^9.0.1",

projects/customizations-example/src/app/app.component.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,3 +275,16 @@
275275
[isQuoted]="isQuoted"
276276
></app-message-text>
277277
</ng-template>
278+
279+
<ng-template
280+
#messageBlocked
281+
let-message="message"
282+
let-isMyMessage="isMyMessage"
283+
>
284+
<ng-container *ngIf="isMyMessage; else othersMessage">
285+
You message was blocked by moderation policies.
286+
</ng-container>
287+
<ng-template #othersMessage>
288+
Message from {{ message.user.name }} was blocked by moderation policies.
289+
</ng-template>
290+
</ng-template>

projects/customizations-example/src/app/app.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
ChannelPreviewInfoContext,
3838
MessageReactionsSelectorComponent,
3939
MessageTextContext,
40+
MessageBlockedContext,
4041
} from 'stream-chat-angular';
4142
import { environment } from '../environments/environment';
4243

@@ -98,6 +99,8 @@ export class AppComponent implements AfterViewInit {
9899
private emptyThreadMessageListTemplate!: TemplateRef<void>;
99100
@ViewChild('messageText')
100101
messageTextTemplate!: TemplateRef<MessageTextContext>;
102+
@ViewChild('messageBlocked')
103+
messageBlockedTemplate!: TemplateRef<MessageBlockedContext>;
101104

102105
constructor(
103106
private chatService: ChatClientService,
@@ -195,6 +198,9 @@ export class AppComponent implements AfterViewInit {
195198
this.customTemplatesService.messageTextTemplate$.next(
196199
this.messageTextTemplate
197200
);
201+
this.customTemplatesService.messageBlockedTemplate$.next(
202+
this.messageBlockedTemplate
203+
);
198204
}
199205

200206
inviteClicked(channel: Channel) {

projects/stream-chat-angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"@breezystack/lamejs": "^1.2.7",
2323
"@ngx-translate/core": "^14.0.0 || ^15.0.0",
2424
"rxjs": "^7.4.0",
25-
"stream-chat": "^8.44.0"
25+
"stream-chat": "^8.60.0"
2626
},
2727
"peerDependenciesMeta": {
2828
"@breezystack/lamejs": {

projects/stream-chat-angular/src/assets/i18n/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,7 @@ export const en = {
131131
'You currently have {{count}} attachments, the maximum is {{max}}':
132132
'You currently have {{count}} attachments, the maximum is {{max}}',
133133
'and others': 'and others',
134+
'Message was blocked by moderation policies':
135+
'Message was blocked by moderation policies',
134136
},
135137
};

projects/stream-chat-angular/src/lib/custom-templates.service.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
MentionTemplateContext,
2424
MessageActionBoxItemContext,
2525
MessageActionsBoxContext,
26+
MessageBlockedContext,
2627
MessageContext,
2728
MessageReactionsContext,
2829
MessageReactionsSelectorContext,
@@ -149,7 +150,7 @@ export class CustomTemplatesService<
149150
TemplateRef<MessageActionsBoxContext> | undefined
150151
>(undefined);
151152
/**
152-
* The template used for displaying an item in the [message actions box](/chat/docs/sdk/angular/components/MessageActionsBoxComponent/)
153+
* The template used for displaying an item in the [message actions box](/chat/docs/angular/components/MessageActionsBoxComponent/)
153154
*
154155
*/
155156
messageActionsBoxItemTemplate$ = new BehaviorSubject<
@@ -366,5 +367,14 @@ export class CustomTemplatesService<
366367
TemplateRef<MessageTextContext> | undefined
367368
>(undefined);
368369

370+
/**
371+
* The template used to display blocked messages that have been removed by moderation policies instead of the default [message blocked component](/chat/docs/sdk/angular/components/MessageBlockedComponent/)
372+
*
373+
* The template has no effect if you're using a custom `messageTemplate$`
374+
*/
375+
messageBlockedTemplate$ = new BehaviorSubject<
376+
TemplateRef<MessageBlockedContext> | undefined
377+
>(undefined);
378+
369379
constructor() {}
370380
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<div
2+
class="str-chat__message str-chat__message-simple str-chat__message--blocked"
3+
[class.str-chat__message--me]="isMyMessage"
4+
[class.str-chat__message-simple--me]="isMyMessage"
5+
[class.str-chat__message--other]="!isMyMessage"
6+
[attr.data-testid]="'message-blocked-component'"
7+
>
8+
<div class="str-chat__message--blocked-inner">
9+
{{ "streamChat.Message was blocked by moderation policies" | translate }}
10+
</div>
11+
</div>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { TranslateModule } from '@ngx-translate/core';
3+
import { MessageBlockedComponent } from './message-blocked.component';
4+
import { ChangeDetectionStrategy } from '@angular/core';
5+
6+
describe('MessageBlockedComponent', () => {
7+
let component: MessageBlockedComponent;
8+
let fixture: ComponentFixture<MessageBlockedComponent>;
9+
let nativeElement: HTMLElement;
10+
11+
beforeEach(async () => {
12+
await TestBed.configureTestingModule({
13+
imports: [TranslateModule.forRoot()],
14+
declarations: [MessageBlockedComponent],
15+
})
16+
.overrideComponent(MessageBlockedComponent, {
17+
set: { changeDetection: ChangeDetectionStrategy.Default },
18+
})
19+
.compileComponents();
20+
});
21+
22+
beforeEach(() => {
23+
fixture = TestBed.createComponent(MessageBlockedComponent);
24+
component = fixture.componentInstance;
25+
nativeElement = fixture.nativeElement as HTMLElement;
26+
fixture.detectChanges();
27+
});
28+
29+
it('should create', () => {
30+
expect(component).toBeTruthy();
31+
});
32+
33+
it('should display the blocked message text', () => {
34+
const blockedMessageElement = nativeElement.querySelector(
35+
'[data-testid="message-blocked-component"]'
36+
);
37+
expect(blockedMessageElement).not.toBeNull();
38+
expect(blockedMessageElement?.textContent?.trim()).toContain(
39+
'streamChat.Message was blocked by moderation policies'
40+
);
41+
});
42+
43+
it('should apply "me" classes when isMyMessage is true', () => {
44+
component.isMyMessage = true;
45+
fixture.detectChanges();
46+
47+
const messageElement = nativeElement.querySelector(
48+
'[data-testid="message-blocked-component"]'
49+
);
50+
expect(
51+
messageElement?.classList.contains('str-chat__message--me')
52+
).toBeTrue();
53+
expect(
54+
messageElement?.classList.contains('str-chat__message-simple--me')
55+
).toBeTrue();
56+
expect(
57+
messageElement?.classList.contains('str-chat__message--other')
58+
).toBeFalse();
59+
});
60+
61+
it('should apply "other" class when isMyMessage is false', () => {
62+
component.isMyMessage = false;
63+
fixture.detectChanges();
64+
65+
const messageElement = nativeElement.querySelector(
66+
'[data-testid="message-blocked-component"]'
67+
);
68+
expect(
69+
messageElement?.classList.contains('str-chat__message--me')
70+
).toBeFalse();
71+
expect(
72+
messageElement?.classList.contains('str-chat__message-simple--me')
73+
).toBeFalse();
74+
expect(
75+
messageElement?.classList.contains('str-chat__message--other')
76+
).toBeTrue();
77+
});
78+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
2+
import { StreamMessage } from '../types';
3+
4+
/**
5+
* The `MessageBlocked` component displays a message that has been blocked by moderation policies.
6+
*/
7+
@Component({
8+
selector: 'stream-message-blocked',
9+
templateUrl: './message-blocked.component.html',
10+
styles: [],
11+
changeDetection: ChangeDetectionStrategy.OnPush,
12+
})
13+
export class MessageBlockedComponent {
14+
@Input() message: StreamMessage | undefined;
15+
@Input() isMyMessage = false;
16+
}

0 commit comments

Comments
 (0)