Skip to content

[CLNP-6715]Added markAsUnread #1347

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

Merged
merged 24 commits into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
22a1023
added markAsUnread
danney-chun Jun 26, 2025
443585b
added undefined check
danney-chun Jul 2, 2025
1d8a45e
fixed QA
danney-chun Jul 3, 2025
4adcdef
Merge branch 'origin/feat/CLNP-6715-Added-Mark-As-Unread' into origin…
danney-chun Jul 3, 2025
b3176bb
Merge pull request #1350 from sendbird/origin/feat/markAsUnread#2
danney-chun Jul 3, 2025
273bd72
fixed etc
danney-chun Jul 4, 2025
7f80ed9
Update MessageView.tsx
danney-chun Jul 4, 2025
66865f6
apply feed
danney-chun Jul 9, 2025
5e81621
fixed lint
danney-chun Jul 9, 2025
66b1ddc
Merge pull request #1351 from sendbird/origin/bug-fix/clnp-7113
danney-chun Jul 9, 2025
7b6f6e2
clnp 7139 (#1353)
danney-chun Jul 10, 2025
b148411
Merge branch 'main' into origin/feat/CLNP-6715-Added-Mark-As-Unread
danney-chun Jul 10, 2025
8e7971d
removed console log
danney-chun Jul 15, 2025
0fe074d
fixed QA Issue (CLNP-7115)
danney-chun Jul 16, 2025
ec05334
New Message -> New Messages
danney-chun Jul 16, 2025
826421c
Fixed QA Issue (#1356)
danney-chun Jul 18, 2025
2ccdbd7
fix lint
danney-chun Jul 18, 2025
ecd21ad
apply feed
danney-chun Jul 18, 2025
60df8b1
fixed QA Issue
danney-chun Jul 21, 2025
c9fa77f
fixed QA Issue
danney-chun Jul 21, 2025
11b0956
added enable mark as unread uikit options 250724 (#1359)
danney-chun Jul 24, 2025
531f7f9
fixed QA issue[CLNP-7397]
danney-chun Jul 30, 2025
e7112c3
fixed bug after click unread floating button, when receive new messag…
danney-chun Jul 30, 2025
4571015
Merge branch 'main' into origin/feat/CLNP-6715-Added-Mark-As-Unread
danney-chun Jul 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib/Sendbird/context/SendbirdProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ const SendbirdContextManager = ({
suggestedRepliesDirection: configs.groupChannel.channel.suggestedRepliesDirection,
enableMarkdownForUserMessage: configs.groupChannel.channel.enableMarkdownForUserMessage,
enableFormTypeMessage: configs.groupChannel.channel.enableFormTypeMessage,
enableMarkAsUnread: configs.groupChannel.channel.enableMarkAsUnread,
enableReactionsSupergroup: sdkInitialized && configsWithAppAttr(sdk).groupChannel.channel.enableReactionsSupergroup as never,
},
groupChannelList: {
Expand Down
1 change: 1 addition & 0 deletions src/lib/Sendbird/context/initialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const config: SendbirdStateConfig = {
suggestedRepliesDirection: 'vertical',
enableMarkdownForUserMessage: false,
enableFormTypeMessage: false,
enableMarkAsUnread: false,
enableReactionsSupergroup: undefined as never, // @deprecated
},
groupChannelList: {
Expand Down
1 change: 1 addition & 0 deletions src/lib/Sendbird/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ export interface SendbirdStateConfig {
suggestedRepliesDirection: SBUConfig['groupChannel']['channel']['suggestedRepliesDirection'];
enableMarkdownForUserMessage: SBUConfig['groupChannel']['channel']['enableMarkdownForUserMessage'];
enableFormTypeMessage: SBUConfig['groupChannel']['channel']['enableFormTypeMessage'];
enableMarkAsUnread: SBUConfig['groupChannel']['channel']['enableMarkAsUnread'];
/**
* @deprecated Currently, this feature is turned off by default. If you wish to use this feature, contact us: {@link https://dashboard.sendbird.com/settings/contact_us?category=feedback_and_feature_requests&product=UIKit}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import NewMessageCount from '../../../GroupChannel/components/NewMessageCountFloatingButton';

export default NewMessageCount;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import UnreadCountFloatingButton from '../../../GroupChannel/components/UnreadCountFloatingButton';

export default UnreadCountFloatingButton;
17 changes: 17 additions & 0 deletions src/modules/Channel/context/ChannelProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, {
useRef,
useMemo,
} from 'react';
import { UIKitConfigProvider, useUIKitConfig } from '@sendbird/uikit-tools';

import type { GroupChannel, Member } from '@sendbird/chat/groupChannel';
import type {
Expand Down Expand Up @@ -52,6 +53,7 @@ import { PublishingModuleType } from '../../internalInterfaces';
import { ChannelActionTypes } from './dux/actionTypes';
import useSendbird from '../../../lib/Sendbird/context/hooks/useSendbird';
import { useLocalization } from '../../../lib/LocalizationContext';
import { uikitConfigStorage } from '../../../lib/utils/uikitConfigStorage';

export { ThreadReplySelectType } from './const'; // export for external usage

Expand Down Expand Up @@ -215,6 +217,7 @@ const ChannelProvider = (props: ChannelContextProps) => {
const sdk = globalStore?.stores?.sdkStore?.sdk;
const sdkInit = globalStore?.stores?.sdkStore?.initialized;
const globalConfigs = globalStore?.config;
const { configs: uikitConfig } = useUIKitConfig();

const [initialTimeStamp, setInitialTimeStamp] = useState(startingPoint);
useEffect(() => {
Expand Down Expand Up @@ -441,6 +444,19 @@ const ChannelProvider = (props: ChannelContextProps) => {
});

return (
<UIKitConfigProvider
storage={uikitConfigStorage}
localConfigs={{
...uikitConfig,
groupChannel: {
...uikitConfig.groupChannel,
channel: {
...uikitConfig.groupChannel.channel,
enableMarkAsUnread: false,
},
},
}
}>
<ChannelContext.Provider value={{
// props
channelUrl,
Expand Down Expand Up @@ -519,6 +535,7 @@ const ChannelProvider = (props: ChannelContextProps) => {
{children}
</UserProfileProvider>
</ChannelContext.Provider>
</UIKitConfigProvider>
);
};

Expand Down
6 changes: 6 additions & 0 deletions src/modules/Channel/context/dux/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const ON_MESSAGE_DELETED_BY_REQ_ID = 'ON_MESSAGE_DELETED_BY_REQ_ID';
export const SET_CURRENT_CHANNEL = 'SET_CURRENT_CHANNEL';
export const SET_CHANNEL_INVALID = 'SET_CHANNEL_INVALID';
export const MARK_AS_READ = 'MARK_AS_READ';
export const MARK_AS_UNREAD = 'MARK_AS_UNREAD';
export const ON_REACTION_UPDATED = 'ON_REACTION_UPDATED';
export const SET_EMOJI_CONTAINER = 'SET_EMOJI_CONTAINER';
export const MESSAGE_LIST_PARAMS_CHANGED = 'MESSAGE_LIST_PARAMS_CHANGED';
Expand Down Expand Up @@ -77,6 +78,11 @@ type CHANNEL_PAYLOAD_TYPES = {
[RESEND_MESSAGE_START]: SendableMessageType;
[MARK_AS_READ]: {
channel: null | GroupChannel;
userIds?: null |string[];
};
[MARK_AS_UNREAD]: {
channel: null | GroupChannel;
userIds?: null |string[];
};
[ON_MESSAGE_DELETED]: MessageId;
[ON_MESSAGE_DELETED_BY_REQ_ID]: RequestId;
Expand Down
25 changes: 25 additions & 0 deletions src/modules/Channel/context/hooks/useHandleChannelEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,31 @@ function useHandleChannelEvents({
});
}
},
onUserMarkedRead: (channel, userIds) => {
logger.info('Channel | useHandleChannelEvents: onUserMarkedAsRead', channel, userIds);
if (compareIds(channel?.url, channelUrl)) {
messagesDispatcher({
type: messageActions.MARK_AS_READ,
payload: {
channel,
userIds,
},
});
}
},
onUserMarkedUnread: (channel, userIds) => {
logger.info('Channel | useHandleChannelEvents: onUserMarkedUnread', channel, userIds);
// TODO:: MADOKA 이 부분에 대해서 명확하게 확인해야 함.
if (compareIds(channel?.url, channelUrl)) {
messagesDispatcher({
type: messageActions.MARK_AS_UNREAD,
payload: {
channel,
userIds,
},
});
}
},
// before(onDeliveryReceiptUpdated)
onUndeliveredMemberStatusUpdated: (channel) => {
if (compareIds(channel?.url, channelUrl)) {
Expand Down
20 changes: 20 additions & 0 deletions src/modules/GroupChannel/components/Message/MessageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import SuggestedMentionListView from '../SuggestedMentionList/SuggestedMentionLi
import type { OnBeforeDownloadFileMessageType } from '../../context/types';
import { classnames, deleteNullish } from '../../../../utils/utils';
import useSendbird from '../../../../lib/Sendbird/context/hooks/useSendbird';
import NewMessageIndicator from '../../../../ui/NewMessageSeparator';

export interface MessageProps {
message: EveryMessage;
hasSeparator?: boolean;
hasNewMessageSeparator?: boolean;
chainTop?: boolean;
chainBottom?: boolean;
handleScroll?: (isBottomMessageAffected?: boolean) => void;
Expand All @@ -49,6 +51,10 @@ export interface MessageProps {
* A function that customizes the rendering of the edit input portion of the message component.
* */
renderEditInput?: () => React.ReactElement;
/**
* A function that is called when the new message separator visibility changes.
*/
onNewMessageSeparatorVisibilityChange?: (isVisible: boolean) => void;
/**
* @deprecated Please use `children` instead
* @description Customizes all child components of the message.
Expand Down Expand Up @@ -79,6 +85,7 @@ export interface MessageViewProps extends MessageProps {
updateUserMessage: (messageId: number, params: UserMessageUpdateParams) => void;
resendMessage: (failedMessage: SendableMessageType) => void;
deleteMessage: (message: CoreMessageType) => Promise<void>;
markAsUnread?: (message: SendableMessageType) => void;

renderFileViewer: (props: { message: FileMessage; onCancel: () => void }) => React.ReactElement;
renderRemoveMessageModal?: (props: { message: EveryMessage; onCancel: () => void }) => React.ReactElement;
Expand Down Expand Up @@ -107,9 +114,11 @@ const MessageView = (props: MessageViewProps) => {
message,
children,
hasSeparator,
hasNewMessageSeparator,
chainTop,
chainBottom,
handleScroll,
onNewMessageSeparatorVisibilityChange,

// MessageViewProps
channel,
Expand All @@ -132,6 +141,7 @@ const MessageView = (props: MessageViewProps) => {
updateUserMessage,
resendMessage,
deleteMessage,
markAsUnread,

setAnimatedMessageId,
animatedMessageId,
Expand Down Expand Up @@ -288,6 +298,7 @@ const MessageView = (props: MessageViewProps) => {
onMessageHeightChange: handleScroll,
onBeforeDownloadFileMessage,
filterEmojiCategoryIds,
markAsUnread,
})}
{ /* Suggested Replies */ }
{
Expand Down Expand Up @@ -415,6 +426,15 @@ const MessageView = (props: MessageViewProps) => {
</Label>
</DateSeparator>
))}
{/* new message indicator */}
{hasNewMessageSeparator
&& (
<NewMessageIndicator onVisibilityChange={onNewMessageSeparatorVisibilityChange}>
<Label type={LabelTypography.CAPTION_2} color={LabelColors.PRIMARY}>
New Message
</Label>
</NewMessageIndicator>
)}
{renderChildren()}
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions src/modules/GroupChannel/components/Message/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const Message = (props: MessageProps): React.ReactElement => {
onMessageAnimated,
onBeforeDownloadFileMessage,
messages,
markAsUnread,
},
actions: {
toggleReaction,
Expand Down Expand Up @@ -85,6 +86,7 @@ export const Message = (props: MessageProps): React.ReactElement => {
updateUserMessage={updateUserMessage}
resendMessage={resendMessage}
deleteMessage={deleteMessage as any}
markAsUnread={markAsUnread}
animatedMessageId={animatedMessageId}
setAnimatedMessageId={setAnimatedMessageId}
onMessageAnimated={onMessageAnimated}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ export const MessageInputWrapperView = React.forwardRef((
)}
{quoteMessage && (
<div className="sendbird-message-input-wrapper__quote-message-input">
<QuoteMessageInput replyingMessage={quoteMessage} onClose={() => setQuoteMessage(null)} />
<QuoteMessageInput replyingMessage={quoteMessage} onClose={() => {
setQuoteMessage(null);
}} />
</div>
)}
{showVoiceMessageInput ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ export interface GetMessagePartsInfoProps {
currentMessage: CoreMessageType;
currentChannel?: GroupChannel | null;
replyType?: string;
hasPrevious?: boolean;
firstUnreadMessageId?: number | string | undefined;
isCurrentDeviceMessage?: boolean;
}

interface OutPuts {
chainTop: boolean,
chainBottom: boolean,
hasSeparator: boolean,
hasNewMessageSeparator: boolean,
}

/**
Expand All @@ -33,6 +37,8 @@ export const getMessagePartsInfo = ({
currentMessage,
currentChannel = null,
replyType = '',
firstUnreadMessageId,
isCurrentDeviceMessage,
}: GetMessagePartsInfoProps): OutPuts => {
const previousMessage = allMessages[currentIndex - 1];
const nextMessage = allMessages[currentIndex + 1];
Expand All @@ -47,9 +53,13 @@ export const getMessagePartsInfo = ({

// https://stackoverflow.com/a/41855608
const hasSeparator = isLocalMessage ? false : !(previousMessageCreatedAt && (isSameDay(currentCreatedAt, previousMessageCreatedAt)));

const hasNewMessageSeparator = !isCurrentDeviceMessage && firstUnreadMessageId === currentMessage.messageId;

return {
chainTop,
chainBottom,
hasSeparator,
hasNewMessageSeparator,
};
};
Loading