Skip to main content

Pin Indicator and Permissions

In this example, we will demonstrate how to create a custom pin indicator component for pinned messages, as well as set custom permissions for pinning.

Pin Permissions#

Stream provides a default set of pin permissions for each user type within each channel type:

export const defaultPinPermissions: PinPermissions = {  commerce: {    admin: true,    anonymous: false,    channel_member: false,    channel_moderator: true,    guest: false,    member: false,    moderator: true,    owner: true,    user: false,  },  gaming: {    admin: true,    anonymous: false,    channel_member: false,    channel_moderator: true,    guest: false,    member: false,    moderator: true,    owner: false,    user: false,  },  livestream: {    admin: true,    anonymous: false,    channel_member: false,    channel_moderator: true,    guest: false,    member: false,    moderator: true,    owner: true,    user: false,  },  messaging: {    admin: true,    anonymous: false,    channel_member: true,    channel_moderator: true,    guest: false,    member: true,    moderator: true,    owner: true,    user: false,  },  team: {    admin: true,    anonymous: false,    channel_member: true,    channel_moderator: true,    guest: false,    member: true,    moderator: true,    owner: true,    user: false,  },};
important

When using a custom channel type, these permissions must be set for each user role.

If you want to use different user permissions or create a custom channel type, the new permissions would need to be passed to MessageList using the pinPermissions prop.

const CustomPermissions = {  customChannelType: {    admin: true,    anonymous: false,    channel_member: false,    channel_moderator: true,    guest: false,    member: false,    moderator: true,    owner: true,    user: false,  },};
<MessageList pinPermissions={CustomPermissions} />

Custom Pin Indicator#

To utilize pinned messages, we will create a basic message component as well as a custom pin indicator to display when a message has been pinned. The custom pin indicator component will simply display the text 'pinned'. This is where you could get creative with custom icons and styles.

export const CustomPinIndicator = () => {  return (    <div>      <div className='pin-text'>pinned</div>    </div>  );};
.pin-text {  font-style: italic;  color: grey;}

This component can now be passed to Channel and later pulled from the ComponentContext when used.

<Channel PinIndicator={CustomPinIndicator}>{/* children of Channel component */}</Channel>

Now we will build a message component that changes its background from turquoise to yellow when a message is pinned. Our custom pin indicator will also replace the MessageOptions component unless the message is currently being hovered.

export const CustomMessage = () => {  const [hovering, setHovering] = useState(false);
  const { message } = useMessageContext();  const { PinIndicator = DefaultPinIndicator } = useComponentContext();
  const messageWrapperRef = useRef<HTMLDivElement>(null);
  const { pinned } = message;
  return (    <div      className={pinned ? 'pinned-custom-message-wrapper' : 'custom-message-wrapper'}      onMouseEnter={() => setHovering(true)}      onMouseLeave={() => setHovering(false)}    >      <div className='custom-message-wrapper-content'>        <div className='custom-message-header'>          <div className='custom-message-header-name'>{message.user?.name || message.user?.id}</div>        </div>        <MessageText />        <MessageRepliesCountButton reply_count={message.reply_count} />      </div>      <div className='custom-message-right-wrapper'>        {hovering ? (          <MessageOptions messageWrapperRef={messageWrapperRef} />        ) : (          pinned && <PinIndicator />        )}      </div>    </div>  );};
.custom-message-wrapper {  display: flex;  padding: 12px;  width: fit-content;  border-radius: 16px;}
.custom-message-wrapper-content {  display: flex;  flex-direction: column;  width: 100%;}
.right-wrapper {  margin-left: 80px;  margin-right: 16px;  width: 48px;}
.custom-message-header-name {  color: black;  font-weight: bold;  font-size: 14;}
.str-chat__message-text-inner {  color: grey;  background: white;  border: none;  padding: 0;}
.str-chat__message-simple__actions {  display: flex;}
.custom-message-wrapper {  background: turquoise;  box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.07);}
.custom-message-wrapper:hover .str-chat__message-text-inner {  background: turquoise;}
.str-chat__message-replies-count-button {  align-self: flex-start;}
/** Pinned Message */
.pinned-custom-message-wrapper {  display: flex;  padding: 12px;  width: fit-content;  border-radius: 16px;}
.pinned-custom-message-wrapper {  background: papayawhip;  box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.07);}
.pinned-custom-message-wrapper:hover .str-chat__message-text-inner {  background: papayawhip;}
.pinned-custom-message-wrapper .str-chat__message-text-inner {  background: papayawhip;}

From here all we need to do is override the default component in Channel at the App.tsx level:

<Channel Message={CustomMessage}>{/* children of Channel component */}</Channel>

The Result#

Unpinned Message:

Custom Pin Indicator UI Component for Chat

Pinned Message (not hovered):

Custom Pin Indicator UI Component for Chat

Pinned Message (hovered):

Custom Pin Indicator UI Component for Chat

Did you find this page helpful?