diff --git a/apps/mobile/src/app/screens/home/homedrawer/ChannelApp/index.tsx b/apps/mobile/src/app/screens/home/homedrawer/ChannelApp/index.tsx
index 4853d1c36a..c385bd6835 100644
--- a/apps/mobile/src/app/screens/home/homedrawer/ChannelApp/index.tsx
+++ b/apps/mobile/src/app/screens/home/homedrawer/ChannelApp/index.tsx
@@ -41,18 +41,6 @@ const ChannelAppScreen = memo(({ channelId }: { channelId: string }) => {
true;
`;
- const injectedCSS = `
- (function() {
- var style = document.createElement('style');
- style.innerHTML = \`
- .h-heightTopBar {
- display: none !important;
- }
- \`;
- document.head.appendChild(style);
- })();
- `;
-
return (
{loading && (
@@ -84,7 +72,6 @@ const ChannelAppScreen = memo(({ channelId }: { channelId: string }) => {
await sleep(500);
setLoading(false);
}}
- injectedJavaScript={injectedCSS}
/>
);
diff --git a/libs/components/src/lib/components/ChannelTopbar/index.tsx b/libs/components/src/lib/components/ChannelTopbar/index.tsx
index 7ef56dea25..603fb24439 100644
--- a/libs/components/src/lib/components/ChannelTopbar/index.tsx
+++ b/libs/components/src/lib/components/ChannelTopbar/index.tsx
@@ -169,7 +169,7 @@ const TopBarChannelApps = ({ channel, mode }: ChannelTopbarProps) => {
-
+
{
/>
dispatch(channelAppActions.setEnableVoice(!enableMic))} isTalking={enableMic} />
-
{/* dispatch(channelAppActions.setEnableVideo(!enableVideo))} isEnable={enableVideo} /> */}
-
-
-
-
>
diff --git a/libs/components/src/lib/components/MessageBox/ReactionMentionInput/ReactionMentionInput.tsx b/libs/components/src/lib/components/MessageBox/ReactionMentionInput/ReactionMentionInput.tsx
index 798664ba65..d13944b7ce 100644
--- a/libs/components/src/lib/components/MessageBox/ReactionMentionInput/ReactionMentionInput.tsx
+++ b/libs/components/src/lib/components/MessageBox/ReactionMentionInput/ReactionMentionInput.tsx
@@ -64,6 +64,7 @@ import {
IHashtagOnMessage,
IMarkdownOnMessage,
IMentionOnMessage,
+ MEZON_MENTIONS_COPY_KEY,
MIN_THRESHOLD_CHARS,
MentionDataProps,
MentionReactInputProps,
@@ -82,6 +83,7 @@ import {
formatMentionsToString,
generateMentionItems,
getDisplayMention,
+ getMarkupInsertIndex,
insertStringAt,
parseHtmlAsFormattedText,
parsePastedMentionData,
@@ -93,7 +95,7 @@ import {
} from '@mezon/utils';
import { ChannelStreamMode } from 'mezon-js';
import { ApiMessageMention } from 'mezon-js/api.gen';
-import { KeyboardEvent, ReactElement, RefObject, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import React, { KeyboardEvent, ReactElement, RefObject, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Mention, MentionItem, MentionsInput, OnChangeHandlerFunc } from 'react-mentions';
import { useSelector, useStore } from 'react-redux';
import textFieldEdit from 'text-field-edit';
@@ -770,7 +772,7 @@ export const MentionReactInput = memo((props: MentionReactInputProps): ReactElem
const onPasteMentions = useCallback(
(event: React.ClipboardEvent
) => {
- const pastedData = event.clipboardData.getData('text/mezon-mentions');
+ const pastedData = event.clipboardData.getData(MEZON_MENTIONS_COPY_KEY);
if (!pastedData) return;
@@ -786,7 +788,12 @@ export const MentionReactInput = memo((props: MentionReactInputProps): ReactElem
const transformedText =
pastedContent?.content?.t && pastedContent?.mentions
- ? transformTextWithMentions(pastedContent.content.t, pastedContent.mentions, currentChatUsersEntities, clanRolesEntities)
+ ? transformTextWithMentions(
+ pastedContent.content.t?.slice(startIndex, endIndex),
+ pastedContent.mentions,
+ currentChatUsersEntities,
+ clanRolesEntities
+ )
: pastedContent?.content?.t || '';
const mentionRaw = generateMentionItems(
@@ -796,10 +803,19 @@ export const MentionReactInput = memo((props: MentionReactInputProps): ReactElem
currentInputValueLength
);
+ const { mentionList } = processMention(
+ [...(request?.mentionRaw || []), ...mentionRaw],
+ rolesClan,
+ membersOfChild as ChannelMembersEntity[],
+ membersOfParent as ChannelMembersEntity[]
+ );
+
+ const transformedTextInsertIndex = getMarkupInsertIndex(currentFocusIndex, mentionList, currentChatUsersEntities, clanRolesEntities);
+
setRequestInput(
{
...request,
- valueTextInput: insertStringAt(request?.valueTextInput || '', transformedText || '', currentFocusIndex),
+ valueTextInput: insertStringAt(request?.valueTextInput || '', transformedText || '', transformedTextInsertIndex),
content: insertStringAt(request?.content || '', pastedContent?.content?.t?.slice(startIndex, endIndex) || '', currentFocusIndex),
mentionRaw: [...(request?.mentionRaw || []), ...mentionRaw]
},
@@ -866,7 +882,7 @@ export const MentionReactInput = memo((props: MentionReactInputProps): ReactElem
{
- const pastedData = event.clipboardData.getData('text/mezon-mentions');
+ const pastedData = event.clipboardData.getData(MEZON_MENTIONS_COPY_KEY);
if (pastedData) {
onPasteMentions(event);
event.preventDefault();
@@ -876,12 +892,12 @@ export const MentionReactInput = memo((props: MentionReactInputProps): ReactElem
setPastedContent(pastedText);
}
}}
- onPasteCapture={(event) => {
- if (event.clipboardData.getData('text/mezon-mentions')) {
+ onPasteCapture={async (event) => {
+ if (event.clipboardData.getData(MEZON_MENTIONS_COPY_KEY)) {
event.preventDefault();
} else {
if (props.handlePaste) {
- props.handlePaste(event);
+ await props.handlePaste(event);
}
}
}}
diff --git a/libs/components/src/lib/components/MessageWithUser/MessageContent.tsx b/libs/components/src/lib/components/MessageWithUser/MessageContent.tsx
index 4f2da5e259..44f96d7bf7 100644
--- a/libs/components/src/lib/components/MessageWithUser/MessageContent.tsx
+++ b/libs/components/src/lib/components/MessageWithUser/MessageContent.tsx
@@ -14,6 +14,7 @@ import {
ETypeLinkMedia,
IExtendedMessage,
IMessageWithUser,
+ MEZON_MENTIONS_COPY_KEY,
TypeMessage,
addMention,
convertTimeString,
@@ -21,7 +22,7 @@ import {
isValidEmojiData
} from '@mezon/utils';
import { safeJSONParse } from 'mezon-js';
-import { memo, useCallback } from 'react';
+import React, { memo, useCallback } from 'react';
import { useSelector } from 'react-redux';
import { MessageLine } from './MessageLine';
import { MessageLineSystem } from './MessageLineSystem';
@@ -65,9 +66,23 @@ const MessageContent = memo(({ message, mode, isSearchMessage, isInTopic }: IMes
const handleCopyMessage = useCallback(
(event: React.ClipboardEvent, startIndex: number, endIndex: number) => {
if (message?.content && message?.mentions) {
- const key = 'text/mezon-mentions';
+ const key = MEZON_MENTIONS_COPY_KEY;
const copyData = {
- message: message,
+ message: {
+ ...message,
+ mentions:
+ message?.mentions
+ ?.map((mention) => {
+ if ((mention?.s || 0) >= startIndex && mention?.e && mention?.e <= endIndex) {
+ return {
+ ...mention,
+ s: (mention?.s || 0) - startIndex,
+ e: mention?.e - startIndex
+ };
+ }
+ })
+ ?.filter(Boolean) || []
+ },
startIndex: startIndex,
endIndex: endIndex
};
diff --git a/libs/store/src/index-mobile.ts b/libs/store/src/index-mobile.ts
index e7028e14f2..dddacfad21 100644
--- a/libs/store/src/index-mobile.ts
+++ b/libs/store/src/index-mobile.ts
@@ -13,6 +13,7 @@ export * from './lib/categories/categories.slice';
export * from './lib/channelmembers/AllUsersChannelByAddChannel.slice';
export * from './lib/channelmembers/channel.members';
export * from './lib/channels/channelUser.slice';
+export * from './lib/channels/channelapp.slice';
export * from './lib/channels/channelmeta.slice';
export * from './lib/channels/channels.slice';
export * from './lib/channels/hashtagDm.slice';
@@ -24,6 +25,7 @@ export * from './lib/clanProfile/clanProfile.slice';
export * from './lib/clanWebhook/clanWebhook.slide';
export * from './lib/clans/clanSettingChannel.slice';
export * from './lib/clans/clans.slice';
+export * from './lib/direct/direct.members.meta';
export * from './lib/direct/direct.slice';
export * from './lib/direct/directmeta.slice';
export * from './lib/dmcall/audioCall.slice';
@@ -42,6 +44,8 @@ export * from './lib/giveCoffee/giveCoffee.slice';
export * from './lib/giveCoffee/historyTransaction.slice';
export * from './lib/helpers';
export * from './lib/invite/invite.slice';
+export * from './lib/meet/meet.slice';
+export * from './lib/memoize';
export * from './lib/messages/SeenMessagePool';
export * from './lib/messages/embedMessage.slice';
export * from './lib/messages/messages.slice';
diff --git a/libs/store/src/lib/store-mobile.tsx b/libs/store/src/lib/store-mobile.tsx
index 9da8f7951b..dcddc483a1 100644
--- a/libs/store/src/lib/store-mobile.tsx
+++ b/libs/store/src/lib/store-mobile.tsx
@@ -33,6 +33,7 @@ import { canvasReducer } from './canvas/canvas.slice';
import { canvasAPIReducer } from './canvas/canvasAPI.slice';
import { userChannelsReducer } from './channelmembers/AllUsersChannelByAddChannel.slice';
import { listchannelsByUserReducer } from './channels/channelUser.slice';
+import { channelAppReducer } from './channels/channelapp.slice';
import { channelMetaReducer } from './channels/channelmeta.slice';
import { hashtagDmReducer } from './channels/hashtagDm.slice';
import { CHANNEL_LIST_RENDER, listChannelRenderReducer } from './channels/listChannelRender.slice';
@@ -40,6 +41,7 @@ import { listUsersByUserReducer } from './channels/listUsers.slice';
import { clanMembersMetaReducer } from './clanMembers/clan.members.meta';
import { integrationClanWebhookReducer } from './clanWebhook/clanWebhook.slide';
import { settingChannelReducer } from './clans/clanSettingChannel.slice';
+import { directMembersMetaReducer } from './direct/direct.members.meta';
import { directMetaReducer } from './direct/directmeta.slice';
import { audioCallReducer } from './dmcall/audioCall.slice';
import { DMCallReducer } from './dmcall/dmcall.slice';
@@ -48,6 +50,7 @@ import { E2EE_FEATURE_KEY, e2eeReducer } from './e2ee/e2ee.slice';
import { errorListenerMiddleware } from './errors/errors.listener';
import { ERRORS_FEATURE_KEY, errorsReducer } from './errors/errors.slice';
import { eventManagementReducer } from './eventManagement/eventManagement.slice';
+import { fcmReducer } from './fcm/fcm.slice';
import { popupForwardReducer } from './forwardMessage/forwardMessage.slice';
import { giveCoffeeReducer } from './giveCoffee/giveCoffee.slice';
import { walletLedgerReducer } from './giveCoffee/historyTransaction.slice';
@@ -56,7 +59,6 @@ import { notifiReactMessageReducer } from './notificationSetting/notificationRea
import { channelCategorySettingReducer, defaultNotificationCategoryReducer } from './notificationSetting/notificationSettingCategory.slice';
import { notificationSettingReducer } from './notificationSetting/notificationSettingChannel.slice';
import { defaultNotificationClanReducer } from './notificationSetting/notificationSettingClan.slice';
-import { ONBOARDING_FEATURE_KEY, onboardingReducer } from './onboarding/onboarding.slice';
import { permissionRoleChannelReducer } from './permissionChannel/permissionRoleChannel.slice';
import { pinMessageReducer } from './pinMessages/pinMessage.slice';
import { OVERRIDDEN_POLICIES_FEATURE_KEY, overriddenPoliciesReducer } from './policies/overriddenPolicies.slice';
@@ -71,7 +73,7 @@ import { toastListenerMiddleware } from './toasts/toasts.listener';
import { TOASTS_FEATURE_KEY, toastsReducer } from './toasts/toasts.slice';
import { topicsReducer } from './topicDiscussion/topicDiscussions.slice';
import { USER_STATUS_API_FEATURE_KEY, userStatusAPIReducer } from './userstatus/userstatusAPI.slice';
-import { voiceReducer } from './voice/voice.slice';
+import { VOICE_FEATURE_KEY, voiceReducer } from './voice/voice.slice';
import { integrationWebhookReducer } from './webhook/webhook.slice';
const persistedReducer = persistReducer(
{
@@ -350,6 +352,15 @@ const persistListChannelRenderReducer = persistReducer(
listChannelRenderReducer
);
+const persistedVoiceReducer = persistReducer(
+ {
+ key: VOICE_FEATURE_KEY,
+ storage,
+ whitelist: ['voiceInfo']
+ },
+ voiceReducer
+);
+
const reducer = {
app: persistedAppReducer,
account: persistAccountReducer,
@@ -365,6 +376,7 @@ const reducer = {
channelMembers: persistedChannelMembersReducer,
listusersbyuserid: persistedListUsersByUserReducer,
threads: persistedThreadReducer,
+ topicdiscussions: persistedTopicReducer,
[SEARCH_MESSAGES_FEATURE_KEY]: searchMessageReducer,
messages: persistedMessageReducer,
categories: persistedCatReducer,
@@ -390,14 +402,16 @@ const reducer = {
isshow: IsShowReducer,
forwardmessage: popupForwardReducer,
notification: notificationReducer,
- voice: voiceReducer,
+ voice: persistedVoiceReducer,
usersstream: usersStreamReducer,
videostream: videoStreamReducer,
+ channelApp: channelAppReducer,
canvas: canvasReducer,
canvasapi: canvasAPIReducer,
activitiesapi: activitiesAPIReducer,
auditlog: auditLogReducer,
audiocall: audioCallReducer,
+ fcm: fcmReducer,
auditlogfilter: auditLogFilterReducer,
references: referencesReducer,
reaction: reactionReducer,
@@ -414,12 +428,11 @@ const reducer = {
giveCoffee: giveCoffeeReducer,
settingClanChannel: settingChannelReducer,
clanMembersMeta: clanMembersMetaReducer,
- [ONBOARDING_FEATURE_KEY]: onboardingReducer,
+ directmembersmeta: directMembersMetaReducer,
dmcall: DMCallReducer,
[USER_STATUS_API_FEATURE_KEY]: userStatusAPIReducer,
[E2EE_FEATURE_KEY]: e2eeReducer,
[EMBED_MESSAGE]: embedReducer,
- topicdiscussions: persistedTopicReducer,
walletLedger: walletLedgerReducer,
[CHANNEL_LIST_RENDER]: persistListChannelRenderReducer
};
diff --git a/libs/utils/src/lib/constant/index.ts b/libs/utils/src/lib/constant/index.ts
index 70d34da6c2..a32cf3e133 100644
--- a/libs/utils/src/lib/constant/index.ts
+++ b/libs/utils/src/lib/constant/index.ts
@@ -100,3 +100,5 @@ export const TOKEN_TO_AMOUNT = {
export const ADD_ROLE_CHANNEL_STATUS = 'Add Role Channel';
export const KOMU_CLAN_ID = '1779484504377790464';
export const WELCOME_CHANNEL_ID = '1827883133219901440';
+
+export const MEZON_MENTIONS_COPY_KEY = 'text/mezon-mentions';
diff --git a/libs/utils/src/lib/utils/index.ts b/libs/utils/src/lib/utils/index.ts
index 389a166a15..2a269e75f3 100644
--- a/libs/utils/src/lib/utils/index.ts
+++ b/libs/utils/src/lib/utils/index.ts
@@ -998,6 +998,42 @@ export const generateMentionItems = (
.filter((item): item is MentionItem => item !== null);
};
+// Calculates the updated insert index when converting from plain text to markup text
+export const getMarkupInsertIndex = (
+ plainInsertIndex: number,
+ mentions: IMentionOnMessage[],
+ usersEntities: Record | Record,
+ clanRoles: Record
+) => {
+ const mentionsBeforeInsert = mentions.filter((mention) => mention?.e && mention?.e <= plainInsertIndex);
+ let totalInsertedLength = 0;
+
+ mentionsBeforeInsert.forEach((mention) => {
+ const { user_id, role_id } = mention;
+
+ if (role_id) {
+ const role = clanRoles?.[role_id as string];
+ if (role) {
+ // Plain text: @name
+ // Mention markup format: @[name](id)
+ // => Adding 4 extra characters: `[`, `]`, `(`, `)`
+ totalInsertedLength += 4 + (role?.id?.length || 0);
+ }
+ return;
+ }
+
+ const user = usersEntities?.[mention.user_id as string];
+ if (user) {
+ // Plain text: @name
+ // Mention markup format: @[name](id)
+ // => Adding 4 extra characters: `[`, `]`, `(`, `)`
+ totalInsertedLength += 4 + (user_id?.length || 0);
+ }
+ });
+
+ return plainInsertIndex + totalInsertedLength;
+};
+
export const parseThreadInfo = (messageContent: string) => {
const match = messageContent.match(/\(([^,]+),\s*([^)]+)\)/);
if (match) {