Skip to content

Commit 1489843

Browse files
Add action buttons component to ChannelPreview
1 parent 8f1a777 commit 1489843

File tree

5 files changed

+138
-40
lines changed

5 files changed

+138
-40
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import type { Channel, ExtendableGenerics } from 'stream-chat';
4+
5+
import { useChannelMembershipState } from '../ChannelList';
6+
import { Icon } from './icons';
7+
8+
export type ChannelPreviewActionButtonsProps<SCG extends ExtendableGenerics> = {
9+
channel: Channel<SCG>;
10+
};
11+
12+
export function ChannelPreviewActionButtons<SCG extends ExtendableGenerics>({
13+
channel,
14+
}: ChannelPreviewActionButtonsProps<SCG>) {
15+
const membership = useChannelMembershipState(channel);
16+
17+
return (
18+
<div className='str-chat__channel-preview__action-buttons'>
19+
<button
20+
className={clsx(
21+
'str-chat__channel-preview__action-button',
22+
'str-chat__channel-preview__action-button--pin',
23+
membership.pinned_at && 'str-chat__channel-preview__action-button--active',
24+
)}
25+
onClick={(e) => {
26+
e.stopPropagation();
27+
if (membership.pinned_at) {
28+
channel.unpin();
29+
} else {
30+
channel.pin();
31+
}
32+
}}
33+
>
34+
<Icon.Pin />
35+
</button>
36+
<button
37+
className={clsx(
38+
'str-chat__channel-preview__action-button',
39+
'str-chat__channel-preview__action-button--archive',
40+
membership.archived_at && 'str-chat__channel-preview__action-button--active',
41+
)}
42+
onClick={(e) => {
43+
e.stopPropagation();
44+
if (membership.archived_at) {
45+
channel.unarchive();
46+
} else {
47+
channel.archive();
48+
}
49+
}}
50+
>
51+
<Icon.ArchiveBox />
52+
</button>
53+
</div>
54+
);
55+
}

src/components/ChannelPreview/ChannelPreviewMessenger.tsx

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import React, { useRef } from 'react';
22
import clsx from 'clsx';
3-
import { Avatar as DefaultAvatar } from '../Avatar';
43

5-
import type { ChannelPreviewUIComponentProps } from './ChannelPreview';
4+
import { ChannelPreviewActionButtons as DefaultChannelPreviewActionButtons } from './ChannelPreviewActionButtons';
5+
import { Avatar as DefaultAvatar } from '../Avatar';
6+
import { useComponentContext } from '../../context';
67
import type { DefaultStreamChatGenerics } from '../../types/types';
8+
import type { ChannelPreviewUIComponentProps } from './ChannelPreview';
79

810
const UnMemoizedChannelPreviewMessenger = <
9-
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
11+
SCG extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
1012
>(
11-
props: ChannelPreviewUIComponentProps<StreamChatGenerics>,
13+
props: ChannelPreviewUIComponentProps<SCG>,
1214
) => {
1315
const {
1416
active,
@@ -25,6 +27,10 @@ const UnMemoizedChannelPreviewMessenger = <
2527
watchers,
2628
} = props;
2729

30+
const {
31+
ChannelPreviewActionButtons = DefaultChannelPreviewActionButtons,
32+
} = useComponentContext<SCG>();
33+
2834
const channelPreviewButton = useRef<HTMLButtonElement | null>(null);
2935

3036
const avatarName =
@@ -42,44 +48,47 @@ const UnMemoizedChannelPreviewMessenger = <
4248
};
4349

4450
return (
45-
<button
46-
aria-label={`Select Channel: ${displayTitle || ''}`}
47-
aria-selected={active}
48-
className={clsx(
49-
`str-chat__channel-preview-messenger str-chat__channel-preview`,
50-
active && 'str-chat__channel-preview-messenger--active',
51-
unread && unread >= 1 && 'str-chat__channel-preview-messenger--unread',
52-
customClassName,
53-
)}
54-
data-testid='channel-preview-button'
55-
onClick={onSelectChannel}
56-
ref={channelPreviewButton}
57-
role='option'
58-
>
59-
<div className='str-chat__channel-preview-messenger--left'>
60-
<Avatar
61-
className='str-chat__avatar--channel-preview'
62-
groupChannelDisplayInfo={groupChannelDisplayInfo}
63-
image={displayImage}
64-
name={avatarName}
65-
/>
66-
</div>
67-
<div className='str-chat__channel-preview-end'>
68-
<div className='str-chat__channel-preview-end-first-row'>
69-
<div className='str-chat__channel-preview-messenger--name'>
70-
<span>{displayTitle}</span>
71-
</div>
72-
{!!unread && (
73-
<div className='str-chat__channel-preview-unread-badge' data-testid='unread-badge'>
74-
{unread}
75-
</div>
76-
)}
51+
<div className='str-chat__channel-preview-container'>
52+
<ChannelPreviewActionButtons channel={channel} />
53+
<button
54+
aria-label={`Select Channel: ${displayTitle || ''}`}
55+
aria-selected={active}
56+
className={clsx(
57+
`str-chat__channel-preview-messenger str-chat__channel-preview`,
58+
active && 'str-chat__channel-preview-messenger--active',
59+
unread && unread >= 1 && 'str-chat__channel-preview-messenger--unread',
60+
customClassName,
61+
)}
62+
data-testid='channel-preview-button'
63+
onClick={onSelectChannel}
64+
ref={channelPreviewButton}
65+
role='option'
66+
>
67+
<div className='str-chat__channel-preview-messenger--left'>
68+
<Avatar
69+
className='str-chat__avatar--channel-preview'
70+
groupChannelDisplayInfo={groupChannelDisplayInfo}
71+
image={displayImage}
72+
name={avatarName}
73+
/>
7774
</div>
78-
<div className='str-chat__channel-preview-messenger--last-message'>
79-
{latestMessagePreview}
75+
<div className='str-chat__channel-preview-end'>
76+
<div className='str-chat__channel-preview-end-first-row'>
77+
<div className='str-chat__channel-preview-messenger--name'>
78+
<span>{displayTitle}</span>
79+
</div>
80+
{!!unread && (
81+
<div className='str-chat__channel-preview-unread-badge' data-testid='unread-badge'>
82+
{unread}
83+
</div>
84+
)}
85+
</div>
86+
<div className='str-chat__channel-preview-messenger--last-message'>
87+
{latestMessagePreview}
88+
</div>
8089
</div>
81-
</div>
82-
</button>
90+
</button>
91+
</div>
8392
);
8493
};
8594

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* eslint-disable react/display-name */
2+
import React from 'react';
3+
import { ComponentPropsWithoutRef } from 'react';
4+
5+
export const Icon = {
6+
ArchiveBox: (props: ComponentPropsWithoutRef<'svg'>) => (
7+
<svg
8+
className='str-chat__icon str-chat__icon--archive-box'
9+
fill='currentColor'
10+
viewBox='0 0 512 512'
11+
xmlns='http://www.w3.org/2000/svg'
12+
{...props}
13+
>
14+
<path d='M32 32l448 0c17.7 0 32 14.3 32 32l0 32c0 17.7-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96L0 64C0 46.3 14.3 32 32 32zm0 128l448 0 0 256c0 35.3-28.7 64-64 64L96 480c-35.3 0-64-28.7-64-64l0-256zm128 80c0 8.8 7.2 16 16 16l160 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-160 0c-8.8 0-16 7.2-16 16z' />
15+
</svg>
16+
),
17+
Pin: (props: ComponentPropsWithoutRef<'svg'>) => (
18+
<svg
19+
className='str-chat__icon str-chat__icon--pin'
20+
fill='currentColor'
21+
viewBox='0 0 384 512'
22+
xmlns='http://www.w3.org/2000/svg'
23+
{...props}
24+
>
25+
<path d='M32 32C32 14.3 46.3 0 64 0L320 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-29.5 0 11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3L32 352c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64 64 64C46.3 64 32 49.7 32 32zM160 384l64 0 0 96c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-96z' />
26+
</svg>
27+
),
28+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './ChannelPreview';
22
export * from './ChannelPreviewMessenger';
3+
export * from './ChannelPreviewActionButtons';
34
export * from './hooks';
45
export * from './utils';

src/context/ComponentContext.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
AttachmentProps,
66
AvatarProps,
77
BaseImageProps,
8+
ChannelPreviewActionButtonsProps,
89
CooldownTimerProps,
910
CustomMessageActionsListProps,
1011
DateSeparatorProps,
@@ -79,6 +80,10 @@ export type ComponentContextValue<
7980
Avatar?: React.ComponentType<AvatarProps<StreamChatGenerics>>;
8081
/** Custom UI component to display <img/> elements resp. a fallback in case of load error, defaults to and accepts same props as: [BaseImage](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/BaseImage.tsx) */
8182
BaseImage?: React.ComponentType<BaseImageProps>;
83+
/** Custom UI component to display set of action buttons within `ChannelPreviewMessenger` component, accepts same props as: [ChannelPreviewActionButtons](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelPreviewActionButtons.tsx) */
84+
ChannelPreviewActionButtons?: React.ComponentType<
85+
ChannelPreviewActionButtonsProps<StreamChatGenerics>
86+
>;
8287
/** Custom UI component to display the slow mode cooldown timer, defaults to and accepts same props as: [CooldownTimer](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/CooldownTimer.tsx) */
8388
CooldownTimer?: React.ComponentType<CooldownTimerProps>;
8489
/** Custom UI component to render set of buttons to be displayed in the MessageActionsBox, defaults to and accepts same props as: [CustomMessageActionsList](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageActions/CustomMessageActionsList.tsx) */

0 commit comments

Comments
 (0)