diff --git a/examples/SampleApp/src/components/Reminders/MessageReminderHeader.tsx b/examples/SampleApp/src/components/Reminders/MessageReminderHeader.tsx
deleted file mode 100644
index f57d827c40..0000000000
--- a/examples/SampleApp/src/components/Reminders/MessageReminderHeader.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import {
- MessageHeaderProps,
- MessagePinnedHeader,
- Time,
- useMessageContext,
- useMessageReminder,
- useStateStore,
- useTheme,
- useTranslationContext,
-} from 'stream-chat-react-native';
-import { ReminderState } from 'stream-chat';
-import { StyleSheet, Text, View } from 'react-native';
-
-const reminderStateSelector = (state: ReminderState) => ({
- timeLeftMs: state.timeLeftMs,
-});
-
-export const MessageReminderHeader = ({ message }: MessageHeaderProps) => {
- const messageId = message?.id ?? '';
- const reminder = useMessageReminder(messageId);
- const { timeLeftMs } = useStateStore(reminder?.state, reminderStateSelector) ?? {};
- const { t } = useTranslationContext();
-
- const {
- theme: { semantics },
- } = useTheme();
-
- const stopRefreshBoundaryMs = reminder?.timer.stopRefreshBoundaryMs;
- const stopRefreshTimeStamp =
- reminder?.remindAt && stopRefreshBoundaryMs
- ? reminder?.remindAt.getTime() + stopRefreshBoundaryMs
- : undefined;
-
- const isBehindRefreshBoundary =
- !!stopRefreshTimeStamp && new Date().getTime() > stopRefreshTimeStamp;
-
- if (!reminder) {
- return null;
- }
-
- // This is for "Saved for Later"
- if (!reminder.remindAt) {
- return (
-
- 🔖 Saved for Later
-
- );
- }
-
- if (reminder.remindAt && timeLeftMs !== null) {
- return (
-
-
-
- {isBehindRefreshBoundary
- ? t('Due since {{ dueSince }}', {
- dueSince: t('timestamp/ReminderNotification', {
- timestamp: reminder.remindAt,
- }),
- })
- : t('Due {{ timeLeft }}', {
- timeLeft: t('duration/Message reminder', {
- milliseconds: timeLeftMs,
- }),
- })}
-
-
- );
- }
-};
-
-export const MessageHeader = () => {
- const { message } = useMessageContext();
- return (
- <>
-
-
- >
- );
-};
-
-const styles = StyleSheet.create({
- headerContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- },
- headerTitle: {
- fontSize: 14,
- fontWeight: '500',
- marginLeft: 4,
- },
-});
diff --git a/examples/SampleApp/src/icons/Bell.tsx b/examples/SampleApp/src/icons/Bell.tsx
deleted file mode 100644
index e2e669941a..0000000000
--- a/examples/SampleApp/src/icons/Bell.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import Svg, { Path } from 'react-native-svg';
-import { useTheme } from 'stream-chat-react-native';
-
-import { IconProps } from '../utils/base';
-
-export const Bell: React.FC = ({ height = 512, width = 512 }) => {
- const {
- theme: {
- semantics
- },
- } = useTheme();
-
- return (
-
- );
-};
diff --git a/examples/SampleApp/src/screens/ChannelScreen.tsx b/examples/SampleApp/src/screens/ChannelScreen.tsx
index 92c178100a..e3b21e5b97 100644
--- a/examples/SampleApp/src/screens/ChannelScreen.tsx
+++ b/examples/SampleApp/src/screens/ChannelScreen.tsx
@@ -27,7 +27,6 @@ import { useChannelMembersStatus } from '../hooks/useChannelMembersStatus';
import type { StackNavigatorParamList } from '../types';
import { NetworkDownIndicator } from '../components/NetworkDownIndicator';
import { useCreateDraftFocusEffect } from '../utils/useCreateDraftFocusEffect.tsx';
-import { MessageHeader } from '../components/Reminders/MessageReminderHeader.tsx';
import { channelMessageActions } from '../utils/messageActions.tsx';
import { MessageLocation } from '../components/LocationSharing/MessageLocation.tsx';
import { useStreamChatContext } from '../context/StreamChatContext.tsx';
@@ -176,7 +175,7 @@ export const ChannelScreen: React.FC = ({
};
const onThreadSelect = useCallback(
- (thread: LocalMessage | null) => {
+ (thread: LocalMessage | null, targetedMessageId?: string) => {
if (!thread || !channel) {
return;
}
@@ -185,6 +184,7 @@ export const ChannelScreen: React.FC = ({
navigation.navigate('ThreadScreen', {
channel,
thread,
+ targetedMessageId,
});
},
[channel, navigation, setThread],
@@ -233,7 +233,6 @@ export const ChannelScreen: React.FC = ({
initialScrollToFirstUnreadMessage
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -300}
messageActions={messageActions}
- MessageHeader={MessageHeader}
MessageLocation={MessageLocation}
messageId={messageId}
NetworkDownIndicator={() => null}
diff --git a/examples/SampleApp/src/screens/ThreadScreen.tsx b/examples/SampleApp/src/screens/ThreadScreen.tsx
index 75fd66e7f3..63a7adb0ca 100644
--- a/examples/SampleApp/src/screens/ThreadScreen.tsx
+++ b/examples/SampleApp/src/screens/ThreadScreen.tsx
@@ -15,12 +15,11 @@ import { useStateStore } from 'stream-chat-react-native';
import { ScreenHeader } from '../components/ScreenHeader';
-import type { RouteProp } from '@react-navigation/native';
+import { type RouteProp } from '@react-navigation/native';
import type { StackNavigatorParamList } from '../types';
import { LocalMessage, ThreadState, UserResponse } from 'stream-chat';
import { useCreateDraftFocusEffect } from '../utils/useCreateDraftFocusEffect.tsx';
-import { MessageReminderHeader } from '../components/Reminders/MessageReminderHeader.tsx';
import { channelMessageActions } from '../utils/messageActions.tsx';
import { useStreamChatContext } from '../context/StreamChatContext.tsx';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
@@ -74,7 +73,7 @@ const ThreadHeader: React.FC = ({ thread }) => {
export const ThreadScreen: React.FC = ({
navigation,
route: {
- params: { channel, thread },
+ params: { channel, thread, targetedMessageId },
},
}) => {
const {
@@ -87,7 +86,6 @@ export const ThreadScreen: React.FC = ({
const { t } = useTranslationContext();
const { setThread } = useStreamChatContext();
const { messageInputFloating, messageListImplementation } = useAppContext();
-
const onPressMessage: NonNullable['onPressMessage']> = (
payload,
) => {
@@ -118,6 +116,13 @@ export const ThreadScreen: React.FC = ({
setThread(null);
}, [setThread]);
+ const onBackPressThread = useCallback(
+ (messageId?: string) => {
+ navigation.popTo('ChannelScreen', { messageId: messageId });
+ },
+ [navigation],
+ );
+
return (
= ({
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -300}
messageActions={messageActions}
messageInputFloating={messageInputFloating}
- MessageHeader={MessageReminderHeader}
MessageLocation={MessageLocation}
onPressMessage={onPressMessage}
thread={thread}
threadList
+ onBackPressThread={onBackPressThread}
+ messageId={targetedMessageId}
>
-
+
);
diff --git a/examples/SampleApp/src/types.ts b/examples/SampleApp/src/types.ts
index 1fc11fc7f6..621ffeb907 100644
--- a/examples/SampleApp/src/types.ts
+++ b/examples/SampleApp/src/types.ts
@@ -40,6 +40,7 @@ export type StackNavigatorParamList = {
ThreadScreen: {
channel: Channel;
thread: LocalMessage | ThreadType;
+ targetedMessageId?: string;
};
};
diff --git a/examples/SampleApp/src/utils/messageActions.tsx b/examples/SampleApp/src/utils/messageActions.tsx
index f104737a4c..0c54000ae3 100644
--- a/examples/SampleApp/src/utils/messageActions.tsx
+++ b/examples/SampleApp/src/utils/messageActions.tsx
@@ -9,8 +9,8 @@ import {
MessageActionsParams,
Time,
TranslationContextValue,
+ Bell,
} from 'stream-chat-react-native';
-import { Bell } from '../icons/Bell';
import { Theme } from 'stream-chat-react-native';
export function channelMessageActions({
@@ -94,7 +94,7 @@ export function channelMessageActions({
},
actionType: reminder ? 'remove-reminder' : 'remind-me',
title: reminder ? 'Remove Reminder' : 'Remind Me',
- icon: ,
+ icon: ,
type: 'standard',
});
actions.push({
diff --git a/package/src/components/Channel/Channel.tsx b/package/src/components/Channel/Channel.tsx
index 7960b7af4d..b6d37ca59a 100644
--- a/package/src/components/Channel/Channel.tsx
+++ b/package/src/components/Channel/Channel.tsx
@@ -141,6 +141,9 @@ import {
} from '../KeyboardCompatibleView/KeyboardControllerAvoidingView';
import { Message as MessageDefault } from '../Message/Message';
import { MessagePinnedHeader as MessagePinnedHeaderDefault } from '../Message/MessageSimple/Headers/MessagePinnedHeader';
+import { MessageReminderHeader as MessageReminderHeaderDefault } from '../Message/MessageSimple/Headers/MessageReminderHeader';
+import { MessageSavedForLaterHeader as MessageSavedForLaterHeaderDefault } from '../Message/MessageSimple/Headers/MessageSavedForLaterHeader';
+import { SentToChannelHeader as SentToChannelHeaderDefault } from '../Message/MessageSimple/Headers/SentToChannelHeader';
import { MessageAvatar as MessageAvatarDefault } from '../Message/MessageSimple/MessageAvatar';
import { MessageBlocked as MessageBlockedDefault } from '../Message/MessageSimple/MessageBlocked';
import { MessageBounce as MessageBounceDefault } from '../Message/MessageSimple/MessageBounce';
@@ -366,6 +369,9 @@ export type ChannelPropsWithContext = Pick &
| 'MessageLocation'
| 'MessageMenu'
| 'MessagePinnedHeader'
+ | 'MessageReminderHeader'
+ | 'MessageSavedForLaterHeader'
+ | 'SentToChannelHeader'
| 'MessageReplies'
| 'MessageRepliesAvatars'
| 'MessageSimple'
@@ -404,7 +410,7 @@ export type ChannelPropsWithContext = Pick &
>
> &
Partial> &
- Partial> & {
+ Partial> & {
shouldSyncChannel: boolean;
thread: ThreadType;
/**
@@ -683,6 +689,9 @@ const ChannelWithContext = (props: PropsWithChildren) =
MessageLocation,
MessageMenu = MessageMenuDefault,
MessagePinnedHeader = MessagePinnedHeaderDefault,
+ MessageReminderHeader = MessageReminderHeaderDefault,
+ MessageSavedForLaterHeader = MessageSavedForLaterHeaderDefault,
+ SentToChannelHeader = SentToChannelHeaderDefault,
MessageReactionPicker = MessageReactionPickerDefault,
MessageReplies = MessageRepliesDefault,
MessageRepliesAvatars = MessageRepliesAvatarsDefault,
@@ -704,6 +713,7 @@ const ChannelWithContext = (props: PropsWithChildren) =
onLongPressMessage,
onPressInMessage,
onPressMessage,
+ onBackPressThread,
openPollCreationDialog,
overrideOwnCapabilities,
PollContent,
@@ -1941,6 +1951,9 @@ const ChannelWithContext = (props: PropsWithChildren) =
MessageLocation,
MessageMenu,
MessagePinnedHeader,
+ MessageReminderHeader,
+ MessageSavedForLaterHeader,
+ SentToChannelHeader,
MessageReactionPicker,
MessageReplies,
MessageRepliesAvatars,
@@ -1984,6 +1997,7 @@ const ChannelWithContext = (props: PropsWithChildren) =
const threadContext = useCreateThreadContext({
allowThreadMessagesInChannel,
+ onBackPressThread,
closeThread,
loadMoreThread,
openThread,
diff --git a/package/src/components/Channel/hooks/useCreateMessagesContext.ts b/package/src/components/Channel/hooks/useCreateMessagesContext.ts
index 2d04824d2e..be64622728 100644
--- a/package/src/components/Channel/hooks/useCreateMessagesContext.ts
+++ b/package/src/components/Channel/hooks/useCreateMessagesContext.ts
@@ -65,6 +65,9 @@ export const useCreateMessagesContext = ({
MessageLocation,
MessageMenu,
MessagePinnedHeader,
+ MessageReminderHeader,
+ MessageSavedForLaterHeader,
+ SentToChannelHeader,
MessageReactionPicker,
MessageReplies,
MessageRepliesAvatars,
@@ -178,6 +181,9 @@ export const useCreateMessagesContext = ({
MessageLocation,
MessageMenu,
MessagePinnedHeader,
+ MessageReminderHeader,
+ MessageSavedForLaterHeader,
+ SentToChannelHeader,
MessageReactionPicker,
MessageReplies,
MessageRepliesAvatars,
diff --git a/package/src/components/Channel/hooks/useCreateThreadContext.ts b/package/src/components/Channel/hooks/useCreateThreadContext.ts
index 43addaafe8..098dbe9596 100644
--- a/package/src/components/Channel/hooks/useCreateThreadContext.ts
+++ b/package/src/components/Channel/hooks/useCreateThreadContext.ts
@@ -12,6 +12,7 @@ const selector = (nextValue: ThreadState) =>
export const useCreateThreadContext = ({
allowThreadMessagesInChannel,
+ onBackPressThread,
closeThread,
loadMoreThread,
openThread,
@@ -39,6 +40,7 @@ export const useCreateThreadContext = ({
return {
allowThreadMessagesInChannel,
+ onBackPressThread,
closeThread,
loadMoreThread,
openThread,
diff --git a/package/src/components/ChannelPreview/ChannelPreviewMessage.tsx b/package/src/components/ChannelPreview/ChannelPreviewMessage.tsx
index 0c363a29f3..ab2b663db0 100644
--- a/package/src/components/ChannelPreview/ChannelPreviewMessage.tsx
+++ b/package/src/components/ChannelPreview/ChannelPreviewMessage.tsx
@@ -79,7 +79,7 @@ export const ChannelPreviewMessage = (props: ChannelPreviewMessageProps) => {
if (draftMessage) {
return (
- {t('Draft:')}
+ {t('Draft')}:
{renderMessagePreview(draftMessage)}
);
diff --git a/package/src/components/Message/Message.tsx b/package/src/components/Message/Message.tsx
index 17c8b7a662..ecbe268e3a 100644
--- a/package/src/components/Message/Message.tsx
+++ b/package/src/components/Message/Message.tsx
@@ -773,6 +773,7 @@ const MessageWithContext = (props: MessagePropsWithContext) => {
}
}
: null,
+ onThreadSelect,
otherAttachments: attachments.other,
preventPress: overlayActive ? true : preventPress,
reactions,
diff --git a/package/src/components/Message/MessageSimple/Headers/MessageReminderHeader.tsx b/package/src/components/Message/MessageSimple/Headers/MessageReminderHeader.tsx
new file mode 100644
index 0000000000..ef06b07e2f
--- /dev/null
+++ b/package/src/components/Message/MessageSimple/Headers/MessageReminderHeader.tsx
@@ -0,0 +1,108 @@
+import React, { useMemo } from 'react';
+
+import { StyleSheet, Text, View } from 'react-native';
+
+import { ReminderState } from 'stream-chat';
+
+import { useMessageContext } from '../../../../contexts/messageContext/MessageContext';
+import { useTheme } from '../../../../contexts/themeContext/ThemeContext';
+import { useTranslationContext } from '../../../../contexts/translationContext/TranslationContext';
+import { useMessageReminder } from '../../../../hooks/useMessageReminder';
+import { useStateStore } from '../../../../hooks/useStateStore';
+import { Bell } from '../../../../icons';
+import { primitives } from '../../../../theme';
+
+const reminderStateSelector = (state: ReminderState) => ({
+ timeLeftMs: state.timeLeftMs,
+});
+
+type MessageReminderHeaderPropsWithContext = {
+ timeLeftMs?: number;
+ isReminderTimeLeft: boolean;
+};
+
+const MessageReminderHeaderWithContext = (props: MessageReminderHeaderPropsWithContext) => {
+ const { timeLeftMs, isReminderTimeLeft } = props;
+ const {
+ theme: { semantics },
+ } = useTheme();
+ const { t } = useTranslationContext();
+ const styles = useStyles();
+
+ return (
+
+
+
+ {isReminderTimeLeft ? t('Reminder set') : t('Reminder overdue')}
+
+ ·
+
+ {t('duration/Message reminder', {
+ milliseconds: timeLeftMs,
+ })}
+
+
+ );
+};
+
+export type MessageReminderHeaderProps = Partial;
+
+export const MessageReminderHeader = (props: MessageReminderHeaderProps) => {
+ const { message } = useMessageContext();
+ const reminder = useMessageReminder(message.id);
+ const { timeLeftMs } = useStateStore(reminder?.state, reminderStateSelector) ?? {};
+
+ const isReminderTimeLeft = !!(timeLeftMs && timeLeftMs > 0);
+
+ return (
+
+ );
+};
+
+const useStyles = () => {
+ const {
+ theme: {
+ semantics,
+ messageSimple: {
+ reminderHeader: { container, label, dot, time },
+ },
+ },
+ } = useTheme();
+
+ return useMemo(() => {
+ return StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ gap: primitives.spacingXxs,
+ paddingVertical: primitives.spacingXxs,
+ ...container,
+ },
+ label: {
+ color: semantics.textPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightSemiBold,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...label,
+ },
+ dot: {
+ color: semantics.textPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightRegular,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...dot,
+ },
+ time: {
+ color: semantics.textPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightRegular,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...time,
+ },
+ });
+ }, [container, semantics, label, dot, time]);
+};
diff --git a/package/src/components/Message/MessageSimple/Headers/MessageSavedForLaterHeader.tsx b/package/src/components/Message/MessageSimple/Headers/MessageSavedForLaterHeader.tsx
new file mode 100644
index 0000000000..96b64554d5
--- /dev/null
+++ b/package/src/components/Message/MessageSimple/Headers/MessageSavedForLaterHeader.tsx
@@ -0,0 +1,55 @@
+import React, { useMemo } from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+
+import { MessageContextValue } from '../../../../contexts/messageContext/MessageContext';
+import { useTheme } from '../../../../contexts/themeContext/ThemeContext';
+import { useTranslationContext } from '../../../../contexts/translationContext/TranslationContext';
+import { Bookmark } from '../../../../icons/Bookmark';
+import { primitives } from '../../../../theme';
+
+export type MessageSavedForLaterHeaderProps = Partial>;
+
+export const MessageSavedForLaterHeader = () => {
+ const {
+ theme: { semantics },
+ } = useTheme();
+ const styles = useStyles();
+ const { t } = useTranslationContext();
+
+ return (
+
+
+ {t('Saved For Later')}
+
+ );
+};
+
+const useStyles = () => {
+ const {
+ theme: {
+ semantics,
+ messageSimple: {
+ savedForLaterHeader: { container, label },
+ },
+ },
+ } = useTheme();
+
+ return useMemo(() => {
+ return StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ gap: primitives.spacingXxs,
+ paddingVertical: primitives.spacingXxs,
+ ...container,
+ },
+ label: {
+ color: semantics.accentPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightSemiBold,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...label,
+ },
+ });
+ }, [semantics, container, label]);
+};
diff --git a/package/src/components/Message/MessageSimple/Headers/SentToChannelHeader.tsx b/package/src/components/Message/MessageSimple/Headers/SentToChannelHeader.tsx
new file mode 100644
index 0000000000..973110ded1
--- /dev/null
+++ b/package/src/components/Message/MessageSimple/Headers/SentToChannelHeader.tsx
@@ -0,0 +1,141 @@
+import React, { useMemo } from 'react';
+
+import { Pressable, StyleSheet, Text, View } from 'react-native';
+
+import { formatMessage } from 'stream-chat';
+
+import {
+ ChannelContextValue,
+ useChannelContext,
+} from '../../../../contexts/channelContext/ChannelContext';
+import { useMessageContext } from '../../../../contexts/messageContext/MessageContext';
+import { useTheme } from '../../../../contexts/themeContext/ThemeContext';
+import { useThreadContext } from '../../../../contexts/threadContext/ThreadContext';
+import { useTranslationContext } from '../../../../contexts/translationContext/TranslationContext';
+import { useStableCallback } from '../../../../hooks';
+import { ArrowUpRight } from '../../../../icons/ArrowUpRight';
+import { primitives } from '../../../../theme';
+
+type SentToChannelHeaderPropsWithContext = Pick & {
+ /**
+ * Function to handle press on the sent to channel header
+ * @returns void
+ */
+ onPress: () => void;
+ /**
+ * Boolean to show the view text
+ * @default false
+ */
+ showViewText?: boolean;
+};
+
+const SentToChannelHeaderWithContext = (props: SentToChannelHeaderPropsWithContext) => {
+ const { threadList, onPress, showViewText } = props;
+ const {
+ theme: { semantics },
+ } = useTheme();
+ const { t } = useTranslationContext();
+ const styles = useStyles();
+
+ return (
+
+
+
+ {threadList ? t('Also sent in channel') : t('Replied to a thread')}
+
+ {showViewText ? (
+ <>
+ ·
+
+ {t('View')}
+
+ >
+ ) : null}
+
+ );
+};
+
+const MemoizedSentToChannelHeader = React.memo(
+ SentToChannelHeaderWithContext,
+) as typeof SentToChannelHeaderWithContext;
+
+export type SentToChannelHeaderProps = Partial;
+
+export const SentToChannelHeader = (props: SentToChannelHeaderProps) => {
+ const { onBackPressThread } = useThreadContext();
+ const { threadList, channel, setTargetedMessage } = useChannelContext();
+ const { onThreadSelect, message } = useMessageContext();
+
+ const handleOnPress = useStableCallback(async () => {
+ if (!threadList) {
+ return await channel
+ .getClient()
+ .search({ cid: channel.cid }, { id: message.parent_id })
+ .then(({ results }) => {
+ if (!results.length) {
+ return;
+ }
+ const targetMessage = formatMessage(results[0].message);
+ onThreadSelect?.(targetMessage, message.id);
+ })
+ .catch((error) => {
+ console.error('Error querying parent message:', error);
+ });
+ } else {
+ setTargetedMessage(message.id);
+ onBackPressThread?.(message.id);
+ }
+ });
+
+ const showViewText = useMemo(() => {
+ return !!((!threadList && onThreadSelect) || (threadList && onBackPressThread));
+ }, [threadList, onThreadSelect, onBackPressThread]);
+
+ return (
+
+ );
+};
+
+const useStyles = () => {
+ const {
+ theme: {
+ semantics,
+ messageSimple: {
+ sentToChannelHeader: { container, label, dot, link },
+ },
+ },
+ } = useTheme();
+
+ return useMemo(() => {
+ return StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ gap: primitives.spacingXxs,
+ paddingVertical: primitives.spacingXxs,
+ ...container,
+ },
+ label: {
+ color: semantics.textPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightSemiBold,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...label,
+ },
+ dot: {
+ color: semantics.textPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightSemiBold,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...dot,
+ },
+ link: {
+ color: semantics.accentPrimary,
+ fontSize: primitives.typographyFontSizeXs,
+ fontWeight: primitives.typographyFontWeightRegular,
+ lineHeight: primitives.typographyLineHeightTight,
+ ...link,
+ },
+ });
+ }, [container, semantics, label, dot, link]);
+};
diff --git a/package/src/components/Message/MessageSimple/Headers/index.tsx b/package/src/components/Message/MessageSimple/Headers/index.tsx
new file mode 100644
index 0000000000..81b226621e
--- /dev/null
+++ b/package/src/components/Message/MessageSimple/Headers/index.tsx
@@ -0,0 +1,4 @@
+export * from './MessagePinnedHeader';
+export * from './MessageReminderHeader';
+export * from './MessageSavedForLaterHeader';
+export * from './SentToChannelHeader';
diff --git a/package/src/components/Message/MessageSimple/MessageHeader.tsx b/package/src/components/Message/MessageSimple/MessageHeader.tsx
index a76f6e2162..2bddd14aad 100644
--- a/package/src/components/Message/MessageSimple/MessageHeader.tsx
+++ b/package/src/components/Message/MessageSimple/MessageHeader.tsx
@@ -1,5 +1,7 @@
import React from 'react';
+import { View } from 'react-native';
+
import {
MessageContextValue,
useMessageContext,
@@ -8,26 +10,82 @@ import {
MessagesContextValue,
useMessagesContext,
} from '../../../contexts/messagesContext/MessagesContext';
+import { useMessageReminder } from '../../../hooks/useMessageReminder';
type MessageHeaderPropsWithContext = Pick &
- Pick;
+ Pick<
+ MessagesContextValue,
+ | 'MessagePinnedHeader'
+ | 'MessageReminderHeader'
+ | 'MessageSavedForLaterHeader'
+ | 'SentToChannelHeader'
+ > & {
+ shouldShowSavedForLaterHeader?: boolean;
+ shouldShowPinnedHeader: boolean;
+ shouldShowReminderHeader: boolean;
+ shouldShowSentToChannelHeader: boolean;
+ };
const MessageHeaderWithContext = (props: MessageHeaderPropsWithContext) => {
- const { message, MessagePinnedHeader } = props;
+ const {
+ message,
+ MessagePinnedHeader,
+ shouldShowSavedForLaterHeader,
+ shouldShowPinnedHeader,
+ shouldShowReminderHeader,
+ shouldShowSentToChannelHeader,
+ MessageReminderHeader,
+ MessageSavedForLaterHeader,
+ SentToChannelHeader,
+ } = props;
- return ;
+ return (
+
+ {shouldShowReminderHeader && }
+ {shouldShowSavedForLaterHeader && }
+ {shouldShowPinnedHeader && }
+ {shouldShowSentToChannelHeader && }
+
+ );
};
const areEqual = (
prevProps: MessageHeaderPropsWithContext,
nextProps: MessageHeaderPropsWithContext,
) => {
- const { message: prevMessage } = prevProps;
- const { message: nextMessage } = nextProps;
+ const {
+ shouldShowSavedForLaterHeader: prevShouldShowSavedForLaterHeader,
+ shouldShowPinnedHeader: prevShouldShowPinnedHeader,
+ shouldShowReminderHeader: prevShouldShowReminderHeader,
+ shouldShowSentToChannelHeader: prevShouldShowSentToChannelHeader,
+ } = prevProps;
+ const {
+ shouldShowSavedForLaterHeader: nextShouldShowSavedForLaterHeader,
+ shouldShowPinnedHeader: nextShouldShowPinnedHeader,
+ shouldShowReminderHeader: nextShouldShowReminderHeader,
+ shouldShowSentToChannelHeader: nextShouldShowSentToChannelHeader,
+ } = nextProps;
+
+ const shouldShowSavedForLaterHeaderEqual =
+ prevShouldShowSavedForLaterHeader === nextShouldShowSavedForLaterHeader;
+ if (!shouldShowSavedForLaterHeaderEqual) {
+ return false;
+ }
- const messageEqual =
- prevMessage.id === nextMessage.id && prevMessage.pinned === nextMessage.pinned;
- if (!messageEqual) {
+ const shouldShowPinnedHeaderEqual = prevShouldShowPinnedHeader === nextShouldShowPinnedHeader;
+ if (!shouldShowPinnedHeaderEqual) {
+ return false;
+ }
+
+ const shouldShowReminderHeaderEqual =
+ prevShouldShowReminderHeader === nextShouldShowReminderHeader;
+ if (!shouldShowReminderHeaderEqual) {
+ return false;
+ }
+
+ const shouldShowSentToChannelHeaderEqual =
+ prevShouldShowSentToChannelHeader === nextShouldShowSentToChannelHeader;
+ if (!shouldShowSentToChannelHeaderEqual) {
return false;
}
@@ -43,9 +101,40 @@ export type MessageHeaderProps = Partial>;
export const MessageHeader = (props: MessageHeaderProps) => {
const { message } = useMessageContext();
- const { MessagePinnedHeader } = useMessagesContext();
+ const {
+ MessagePinnedHeader,
+ MessageReminderHeader,
+ MessageSavedForLaterHeader,
+ SentToChannelHeader,
+ } = useMessagesContext();
+ const reminder = useMessageReminder(message.id);
+
+ const shouldShowSavedForLaterHeader = reminder && !reminder.remindAt;
+ const shouldShowReminderHeader = reminder && reminder.remindAt;
+ const shouldShowPinnedHeader = !!message?.pinned;
+ const shouldShowSentToChannelHeader = !!message?.show_in_channel;
+
+ if (
+ !shouldShowPinnedHeader &&
+ !shouldShowSavedForLaterHeader &&
+ !shouldShowReminderHeader &&
+ !shouldShowSentToChannelHeader
+ ) {
+ return null;
+ }
return (
-
+
);
};
diff --git a/package/src/components/Message/hooks/useCreateMessageContext.ts b/package/src/components/Message/hooks/useCreateMessageContext.ts
index 0484fb0a2e..6fc3953a83 100644
--- a/package/src/components/Message/hooks/useCreateMessageContext.ts
+++ b/package/src/components/Message/hooks/useCreateMessageContext.ts
@@ -41,6 +41,7 @@ export const useCreateMessageContext = ({
onOpenThread,
onPress,
onPressIn,
+ onThreadSelect,
otherAttachments,
preventPress,
reactions,
@@ -92,6 +93,7 @@ export const useCreateMessageContext = ({
onOpenThread,
onPress,
onPressIn,
+ onThreadSelect,
otherAttachments,
preventPress,
reactions,
diff --git a/package/src/components/index.ts b/package/src/components/index.ts
index 81c347a587..a23fc62bac 100644
--- a/package/src/components/index.ts
+++ b/package/src/components/index.ts
@@ -98,7 +98,7 @@ export * from './Message/MessageSimple/MessageDeleted';
export * from './Message/MessageSimple/MessageError';
export * from './Message/MessageSimple/MessageFooter';
export * from './Message/MessageSimple/MessageHeader';
-export * from './Message/MessageSimple/Headers/MessagePinnedHeader';
+export * from './Message/MessageSimple/Headers';
export * from './Message/MessageSimple/MessageReplies';
export * from './Message/MessageSimple/MessageRepliesAvatars';
export * from './Message/MessageSimple/MessageSimple';
diff --git a/package/src/contexts/messageContext/MessageContext.tsx b/package/src/contexts/messageContext/MessageContext.tsx
index 391da93775..043c70b793 100644
--- a/package/src/contexts/messageContext/MessageContext.tsx
+++ b/package/src/contexts/messageContext/MessageContext.tsx
@@ -119,6 +119,15 @@ export type MessageContextValue = {
preventPress?: boolean;
/** Whether or not the avatar show show next to Message */
showAvatar?: boolean;
+ /**
+ * Function to handle thread select
+ * @param message - The message to select
+ * @param targetedMessageId - The id of the targeted message
+ * @returns void
+ *
+ * TODO: V9: Change function params to an object
+ */
+ onThreadSelect?: (message: LocalMessage, targetedMessageId?: string) => void;
} & Pick &
Pick;
diff --git a/package/src/contexts/messagesContext/MessagesContext.tsx b/package/src/contexts/messagesContext/MessagesContext.tsx
index 4dbef94bf8..fb15642f58 100644
--- a/package/src/contexts/messagesContext/MessagesContext.tsx
+++ b/package/src/contexts/messagesContext/MessagesContext.tsx
@@ -30,6 +30,9 @@ import type {
MessageProps,
} from '../../components/Message/Message';
import type { MessagePinnedHeaderProps } from '../../components/Message/MessageSimple/Headers/MessagePinnedHeader';
+import type { MessageReminderHeaderProps } from '../../components/Message/MessageSimple/Headers/MessageReminderHeader';
+import type { MessageSavedForLaterHeaderProps } from '../../components/Message/MessageSimple/Headers/MessageSavedForLaterHeader';
+import type { SentToChannelHeaderProps } from '../../components/Message/MessageSimple/Headers/SentToChannelHeader';
import type { MessageAvatarProps } from '../../components/Message/MessageSimple/MessageAvatar';
import type { MessageBlockedProps } from '../../components/Message/MessageSimple/MessageBlocked';
import type { MessageBounceProps } from '../../components/Message/MessageSimple/MessageBounce';
@@ -237,6 +240,18 @@ export type MessagesContextValue = Pick;
+ /**
+ * Custom message reminder component
+ */
+ MessageReminderHeader: React.ComponentType;
+ /**
+ * Custom message saved for later component
+ */
+ MessageSavedForLaterHeader: React.ComponentType;
+ /**
+ * Custom message sent to channel component
+ */
+ SentToChannelHeader: React.ComponentType;
/**
* UI component for MessageReactionPicker
*/
diff --git a/package/src/contexts/themeContext/utils/theme.ts b/package/src/contexts/themeContext/utils/theme.ts
index 886e9e4790..73ec7ef853 100644
--- a/package/src/contexts/themeContext/utils/theme.ts
+++ b/package/src/contexts/themeContext/utils/theme.ts
@@ -699,6 +699,22 @@ export type Theme = {
container: ViewStyle;
label: TextStyle;
};
+ savedForLaterHeader: {
+ container: ViewStyle;
+ label: TextStyle;
+ };
+ reminderHeader: {
+ container: ViewStyle;
+ label: TextStyle;
+ dot: TextStyle;
+ time: TextStyle;
+ };
+ sentToChannelHeader: {
+ container: ViewStyle;
+ label: TextStyle;
+ dot: TextStyle;
+ link: TextStyle;
+ };
reactionListBottom: {
contentContainer: ViewStyle;
columnWrapper: ViewStyle;
@@ -1539,6 +1555,22 @@ export const defaultTheme: Theme = {
container: {},
label: {},
},
+ savedForLaterHeader: {
+ container: {},
+ label: {},
+ },
+ reminderHeader: {
+ container: {},
+ label: {},
+ dot: {},
+ time: {},
+ },
+ sentToChannelHeader: {
+ container: {},
+ label: {},
+ dot: {},
+ link: {},
+ },
reactionListBottom: {
contentContainer: {},
columnWrapper: {},
diff --git a/package/src/contexts/threadContext/ThreadContext.tsx b/package/src/contexts/threadContext/ThreadContext.tsx
index d60d6b58b1..7270763cb6 100644
--- a/package/src/contexts/threadContext/ThreadContext.tsx
+++ b/package/src/contexts/threadContext/ThreadContext.tsx
@@ -26,6 +26,12 @@ export type ThreadContextValue = {
threadInstance?: Thread | null;
threadLoadingMore?: boolean;
threadLoadingMoreRecent?: boolean;
+ /**
+ * Function to handle back press on thread
+ * @param messageId - The id of the message to go back to
+ * @returns void
+ */
+ onBackPressThread?: (messageId?: string) => void;
};
export const ThreadContext = React.createContext(DEFAULT_BASE_CONTEXT_VALUE as ThreadContextValue);
diff --git a/package/src/i18n/en.json b/package/src/i18n/en.json
index e9640e72fa..43f607545d 100644
--- a/package/src/i18n/en.json
+++ b/package/src/i18n/en.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Device gallery permissions is used to take photos or videos.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Do you want to send a copy of this message to a moderator for further investigation?",
"Due since {{ dueSince }}": "Due since {{ dueSince }}",
- "Due {{ timeLeft }}": "Due {{ timeLeft }}",
"Edit Message": "Edit Message",
"Edited": "Edited",
"Editing Message": "Editing Message",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} Reactions",
"Tap to remove": "Tap to remove",
"Draft": "Draft",
+ "Reminder set": "Reminder set",
+ "Also sent in channel": "Also sent in channel",
+ "Replied to a thread": "Replied to a thread",
+ "View": "View",
+ "Reminder overdue": "Reminder overdue",
"Poll has ended": "Poll has ended"
}
diff --git a/package/src/i18n/es.json b/package/src/i18n/es.json
index acf1fac499..981acfcc62 100644
--- a/package/src/i18n/es.json
+++ b/package/src/i18n/es.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Los permisos de la galería del dispositivo se utilizan para tomar fotos o videos.",
"Do you want to send a copy of this message to a moderator for further investigation?": "¿Deseas enviar una copia de este mensaje a un moderador para una investigación adicional?",
"Due since {{ dueSince }}": "Debido desde {{ dueSince }}",
- "Due {{ timeLeft }}": "Debido {{ timeLeft }}",
"Edit Message": "Editar mensaje",
"Edited": "Editado",
"Editing Message": "Editando mensaje",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} reacciones",
"Tap to remove": "Toca para quitar",
"Draft": "Borrador",
+ "Reminder set": "Recordatorio establecido",
+ "Also sent in channel": "También enviado en el canal",
+ "Replied to a thread": "Respondido a un hilo",
+ "View": "Ver",
+ "Reminder overdue": "Recordatorio vencido",
"Poll has ended": "Votación finalizada"
}
diff --git a/package/src/i18n/fr.json b/package/src/i18n/fr.json
index 57f3ac6fa6..6527b6d296 100644
--- a/package/src/i18n/fr.json
+++ b/package/src/i18n/fr.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Les autorisations de la galerie de l'appareil sont utilisées pour prendre des photos ou des vidéos.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Voulez-vous envoyer une copie de ce message à un modérateur pour une enquête plus approfondie?",
"Due since {{ dueSince }}": "Échéance depuis {{ dueSince }}",
- "Due {{ timeLeft }}": "Échéance {{ timeLeft }}",
"Edit Message": "Éditer un message",
"Edited": "Édité",
"Editing Message": "Édite un message",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} réactions",
"Tap to remove": "Appuyez pour retirer",
"Draft": "Brouillon",
+ "Reminder set": "Recordatorio establecido",
+ "Also sent in channel": "También enviado en el canal",
+ "Replied to a thread": "Respondido a un hilo",
+ "View": "Ver",
+ "Reminder overdue": "Recordatorio vencido",
"Poll has ended": "Vote terminé"
}
diff --git a/package/src/i18n/he.json b/package/src/i18n/he.json
index af03c4a446..b104ee010c 100644
--- a/package/src/i18n/he.json
+++ b/package/src/i18n/he.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "הרשאות גלריית המכשיר משמשות לצילום תמונות או סרטונים.",
"Do you want to send a copy of this message to a moderator for further investigation?": "האם את/ה רוצה לשלוח עותק של הודעה זו למנחה להמשך חקירה?",
"Due since {{ dueSince }}": "מועד אחרון מאז {{ dueSince }}",
- "Due {{ timeLeft }}": "מועד אחרון {{ timeLeft }}",
"Edit Message": "ערוך הודעה",
"Edited": "נערך",
"Editing Message": "הודעה בעריכה",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} תגובות",
"Tap to remove": "הקש כדי להסיר",
"Draft": "טיוטה",
+ "Reminder set": "הזמן הוקם",
+ "Also sent in channel": "שלח/י גם לשיחה",
+ "Replied to a thread": "הגב/י בשרשור",
+ "View": "צפה",
+ "Reminder overdue": "הזמן פג",
"Poll has ended": "ההצבעה הסתיימה"
}
diff --git a/package/src/i18n/hi.json b/package/src/i18n/hi.json
index 380baad4a7..442f144292 100644
--- a/package/src/i18n/hi.json
+++ b/package/src/i18n/hi.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "डिवाइस गैलरी की अनुमतियों का उपयोग फोटो या वीडियो लेने के लिए किया जाता है।",
"Do you want to send a copy of this message to a moderator for further investigation?": "क्या आप इस संदेश की एक प्रति आगे की जाँच के लिए किसी मॉडरेटर को भेजना चाहते हैं?",
"Due since {{ dueSince }}": "{{ dueSince }} से देय है",
- "Due {{ timeLeft }}": "{{ timeLeft }} बचा है",
"Edit Message": "मैसेज में बदलाव करे",
"Edited": "मैसेज बदला गया है",
"Editing Message": "मैसेज बदला जा रहा है",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} प्रतिक्रियाएँ",
"Tap to remove": "हटाने के लिए टैप करें",
"Draft": "ड्राफ्ट",
+ "Reminder set": "रीमिंडर सेट किया गया",
+ "Also sent in channel": "चैनल में भी भेजा गया",
+ "Replied to a thread": "थ्रेड में उत्तर दिया",
+ "View": "देखें",
+ "Reminder overdue": "रीमिंडर ओवरडो",
"Poll has ended": "वोट समाप्त"
}
diff --git a/package/src/i18n/it.json b/package/src/i18n/it.json
index 52358aa6f3..b41c526707 100644
--- a/package/src/i18n/it.json
+++ b/package/src/i18n/it.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Le autorizzazioni della galleria del dispositivo vengono utilizzate per scattare foto o video.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Vuoi inviare una copia di questo messaggio a un moderatore per ulteriori indagini?",
"Due since {{ dueSince }}": "Scadenza dal {{ dueSince }}",
- "Due {{ timeLeft }}": "Scadenza {{ timeLeft }}",
"Edit Message": "Modifica Messaggio",
"Edited": "Modificato",
"Editing Message": "Modificando il Messaggio",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} reazioni",
"Tap to remove": "Tocca per rimuovere",
"Draft": "Borrador",
+ "Reminder set": "Recordatorio establecido",
+ "Also sent in channel": "También enviado en el canal",
+ "Replied to a thread": "Respondido a un hilo",
+ "View": "Ver",
+ "Reminder overdue": "Recordatorio vencido",
"Poll has ended": "Votazione terminata"
}
diff --git a/package/src/i18n/ja.json b/package/src/i18n/ja.json
index 3151695cdc..015821c2a8 100644
--- a/package/src/i18n/ja.json
+++ b/package/src/i18n/ja.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "デバイスギャラリーの権限は写真やビデオを撮るために使用されます。",
"Do you want to send a copy of this message to a moderator for further investigation?": "このメッセージのコピーをモデレーターに送信して、さらに調査しますか?",
"Due since {{ dueSince }}": "期限は {{ dueSince }} からです",
- "Due {{ timeLeft }}": "期限は {{ timeLeft }} です",
"Edit Message": "メッセージを編集",
"Edited": "編集済み",
"Editing Message": "メッセージを編集中",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}}件のリアクション",
"Tap to remove": "タップして削除",
"Draft": "下書き",
+ "Reminder set": "リマインダー設定",
+ "Also sent in channel": "チャンネルにも送信",
+ "Replied to a thread": "スレッドに返信",
+ "View": "表示",
+ "Reminder overdue": "リマインダー期限切れ",
"Poll has ended": "投票終了"
}
diff --git a/package/src/i18n/ko.json b/package/src/i18n/ko.json
index c867997a70..30d39822a4 100644
--- a/package/src/i18n/ko.json
+++ b/package/src/i18n/ko.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "장치 갤러리 권한은 사진 또는 비디오를 촬영하는 데 사용됩니다.",
"Do you want to send a copy of this message to a moderator for further investigation?": "이 메시지의 복사본을 운영자에게 보내 추가 조사를합니까?",
"Due since {{ dueSince }}": "기한은 {{ dueSince }}부터입니다.",
- "Due {{ timeLeft }}": "기한은 {{ timeLeft }}입니다.",
"Edit Message": "메시지 수정",
"Edited": "편집됨",
"Editing Message": "메시지 편집중",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}}개의 반응",
"Tap to remove": "탭하여 제거",
"Draft": "초안",
+ "Reminder set": "리마인더 설정",
+ "Also sent in channel": "채널에도 전송",
+ "Replied to a thread": "스레드에 답장",
+ "View": "보기",
+ "Reminder overdue": "리마인더 만료",
"Poll has ended": "투표 종료됨"
}
diff --git a/package/src/i18n/nl.json b/package/src/i18n/nl.json
index 110f25055f..d8afc01355 100644
--- a/package/src/i18n/nl.json
+++ b/package/src/i18n/nl.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Apparaatgallerijmachtigingen worden gebruikt om foto’s of video’s te maken.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Wil je een kopie van dit bericht naar een moderator sturen voor verder onderzoek?",
"Due since {{ dueSince }}": "Vervaldatum sinds {{ dueSince }}",
- "Due {{ timeLeft }}": "Vervaldatum {{ timeLeft }}",
"Edit Message": "Pas bericht aan",
"Edited": "Bewerkt",
"Editing Message": "Bericht aanpassen",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} reacties",
"Tap to remove": "Tik om te verwijderen",
"Draft": "Ontwerp",
+ "Reminder set": "Reminder set",
+ "Also sent in channel": "Also sent in channel",
+ "Replied to a thread": "Replied to a thread",
+ "View": "View",
+ "Reminder overdue": "Reminder overdue",
"Poll has ended": "Stemmen beëindigd"
}
diff --git a/package/src/i18n/pt-br.json b/package/src/i18n/pt-br.json
index d197d1d594..a2f2fa827f 100644
--- a/package/src/i18n/pt-br.json
+++ b/package/src/i18n/pt-br.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "As permissões da galeria do dispositivo são usadas para tirar fotos ou vídeos.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Deseja enviar uma cópia desta mensagem para um moderador para investigação adicional?",
"Due since {{ dueSince }}": "Vencido desde {{ dueSince }}",
- "Due {{ timeLeft }}": "Vencido {{ timeLeft }}",
"Edit Message": "Editar Mensagem",
"Edited": "Editado",
"Editing Message": "Editando Mensagem",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} reações",
"Tap to remove": "Toque para remover",
"Draft": "Rascunho",
+ "Reminder set": "Recordatorio establecido",
+ "Also sent in channel": "También enviado en el canal",
+ "Replied to a thread": "Respondido a un hilo",
+ "View": "Ver",
+ "Reminder overdue": "Recordatorio vencido",
"Poll has ended": "Votação encerrada"
}
diff --git a/package/src/i18n/ru.json b/package/src/i18n/ru.json
index ba38b33512..bffbac0807 100644
--- a/package/src/i18n/ru.json
+++ b/package/src/i18n/ru.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Разрешения галереи устройства используются для съемки фото или видео.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Вы хотите отправить копию этого сообщения модератору для дальнейшего изучения?",
"Due since {{ dueSince }}": "Срок с {{ dueSince }}",
- "Due {{ timeLeft }}": "Срок {{ timeLeft }}",
"Edit Message": "Редактировать сообщение",
"Edited": "Отредактировано",
"Editing Message": "Редактирование сообщения",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} реакций",
"Tap to remove": "Нажмите, чтобы удалить",
"Draft": "Черновик",
+ "Reminder set": "Напоминание установлено",
+ "Also sent in channel": "Также отправлено в канал",
+ "Replied to a thread": "Ответил на тему",
+ "View": "Посмотреть",
+ "Reminder overdue": "Напоминание просрочено",
"Poll has ended": "Голосование завершено"
}
diff --git a/package/src/i18n/tr.json b/package/src/i18n/tr.json
index 7acbab569f..167d288c06 100644
--- a/package/src/i18n/tr.json
+++ b/package/src/i18n/tr.json
@@ -28,7 +28,6 @@
"Device gallery permissions is used to take photos or videos.": "Cihaz galerisi izinleri fotoğraf veya video çekmek için kullanılır.",
"Do you want to send a copy of this message to a moderator for further investigation?": "Detaylı inceleme için bu mesajın kopyasını moderatöre göndermek istiyor musunuz?",
"Due since {{ dueSince }}": "Son tarihi {{ dueSince }} itibarıyla geçmiştir.",
- "Due {{ timeLeft }}": "Son tarihi {{ timeLeft }}'dir.",
"Edit Message": "Mesajı Düzenle",
"Edited": "Düzenlendi",
"Editing Message": "Mesaj Düzenleniyor",
@@ -173,5 +172,10 @@
"{{count}} Reactions_other": "{{count}} tepki",
"Tap to remove": "Kaldırmak için dokunun",
"Draft": "Taslak",
+ "Reminder set": "Hatırlatıcı ayarlandı",
+ "Also sent in channel": "Kanala da gönderildi",
+ "Replied to a thread": "Konuya yanıt verildi",
+ "View": "Görüntüle",
+ "Reminder overdue": "Hatırlatıcı süresi doldu",
"Poll has ended": "Oylama sona erdi"
}
diff --git a/package/src/icons/ArrowUpRight.tsx b/package/src/icons/ArrowUpRight.tsx
new file mode 100644
index 0000000000..d7cfd21239
--- /dev/null
+++ b/package/src/icons/ArrowUpRight.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
+
+export const ArrowUpRight = ({ height = 16, width = 16, ...rest }: IconProps) => {
+ return (
+
+ );
+};
diff --git a/package/src/icons/Bell.tsx b/package/src/icons/Bell.tsx
new file mode 100644
index 0000000000..095472f198
--- /dev/null
+++ b/package/src/icons/Bell.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
+
+export const Bell = ({ height = 16, width = 16, ...rest }: IconProps) => {
+ return (
+
+ );
+};
diff --git a/package/src/icons/Bookmark.tsx b/package/src/icons/Bookmark.tsx
new file mode 100644
index 0000000000..b2c6766bf3
--- /dev/null
+++ b/package/src/icons/Bookmark.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+
+import { Path, Svg } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
+
+export const Bookmark = ({ height, width, ...rest }: IconProps) => (
+
+);
diff --git a/package/src/icons/index.ts b/package/src/icons/index.ts
index 431c7fe51b..a45b453a2c 100644
--- a/package/src/icons/index.ts
+++ b/package/src/icons/index.ts
@@ -104,3 +104,4 @@ export * from './UnreadIndicator';
export * from './FilePickerIcon';
export * from './CommandsIcon';
export * from './CurveLineLeftUpReply';
+export * from './Bell';