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) {