Skip to content

Commit 28ce030

Browse files
Merge pull request #5740 from nguyentrannhan/develop
Develop
2 parents 14892a0 + b1325c8 commit 28ce030

File tree

10 files changed

+164
-61
lines changed

10 files changed

+164
-61
lines changed

apps/chat/src/app/layouts/ClanLayout.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ChannelList, ChannelTopbar, ClanHeader, FooterProfile, StreamInfo, UpdateButton } from '@mezon/components';
2-
import { useApp, useAppParams } from '@mezon/core';
2+
import { useApp } from '@mezon/core';
33
import {
44
ChannelsEntity,
55
ClansEntity,
@@ -8,7 +8,6 @@ import {
88
selectCloseMenu,
99
selectCurrentChannel,
1010
selectCurrentClan,
11-
selectCurrentStreamInfo,
1211
selectIsElectronDownloading,
1312
selectIsElectronUpdateAvailable,
1413
selectIsInCall,
@@ -43,10 +42,8 @@ const ClanEffects: React.FC<{
4342
}> = ({ currentClan, currentChannel, chatStreamRef, isShowChatStream, isShowCreateThread, isShowCreateTopic, userId, userName }) => {
4443
// move code thanh.levan
4544

46-
const { canvasId } = useAppParams();
4745
const dispatch = useAppDispatch();
4846
const { setIsShowMemberList } = useApp();
49-
const currentStreamInfo = useSelector(selectCurrentStreamInfo);
5047

5148
useEffect(() => {
5249
const updateChatStreamWidth = () => {
@@ -63,12 +60,6 @@ const ClanEffects: React.FC<{
6360
};
6461
}, [isShowChatStream]);
6562

66-
useEffect(() => {
67-
if (!canvasId) {
68-
dispatch(appActions.setIsShowCanvas(false));
69-
}
70-
}, [currentStreamInfo, currentClan, currentChannel, canvasId, dispatch]);
71-
7263
useEffect(() => {
7364
if (isShowCreateThread || isShowCreateTopic) {
7465
setIsShowMemberList(false);

libs/components/src/lib/components/EmbedMessage/components/EmbedOptionRatio.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ export function EmbedOptionRatio({ options, message_id, idRadio }: EmbedOptionRa
4747
id: idRadio,
4848
value: options[index].value
4949
},
50-
multiple: !checkMultiple
50+
multiple: true,
51+
onlyChooseOne: checkMultiple
5152
})
5253
);
5354
},

libs/components/src/lib/components/MarkdownFormatText/MentionUser.tsx

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
/* eslint-disable @nx/enforce-module-boundaries */
2-
import { selectChannelMemberByUserIds, selectCurrentChannel, selectCurrentChannelId, selectDmGroupCurrentId, useAppSelector } from '@mezon/store';
2+
import {
3+
selectChannelMemberByUserIds,
4+
selectCurrentChannel,
5+
selectCurrentChannelId,
6+
selectDmGroupCurrentId,
7+
selectMemberByUsername,
8+
useAppSelector
9+
} from '@mezon/store';
310
import { HEIGHT_PANEL_PROFILE, HEIGHT_PANEL_PROFILE_DM, getNameForPrioritize } from '@mezon/utils';
411
import { ChannelStreamMode, ChannelType } from 'mezon-js';
512
import { RefObject, memo, useCallback, useMemo, useState } from 'react';
@@ -15,6 +22,7 @@ type ChannelHashtagProps = {
1522
isTokenClickAble: boolean;
1623
tagRoleName?: string;
1724
tagRoleId?: string;
25+
mention?: string;
1826
};
1927

2028
enum MentionType {
@@ -31,9 +39,19 @@ type UserProfilePopupProps = {
3139
isDm?: boolean;
3240
rootRef?: RefObject<HTMLElement>;
3341
onClose: () => void;
42+
username?: string;
3443
};
3544

36-
const MentionUser = ({ tagUserName, mode, isJumMessageEnabled, isTokenClickAble, tagUserId, tagRoleName, tagRoleId }: ChannelHashtagProps) => {
45+
const MentionUser = ({
46+
mention,
47+
tagUserName,
48+
mode,
49+
isJumMessageEnabled,
50+
isTokenClickAble,
51+
tagUserId,
52+
tagRoleName,
53+
tagRoleId
54+
}: ChannelHashtagProps) => {
3755
const currentChannelId = useSelector(selectCurrentChannelId);
3856
const displayToken = useMemo(() => {
3957
if (tagRoleId) {
@@ -56,7 +74,13 @@ const MentionUser = ({ tagUserName, mode, isJumMessageEnabled, isTokenClickAble,
5674
type: MentionType.USER_EXIST
5775
};
5876
}
59-
}, [tagUserName, tagRoleName, tagUserId, tagRoleId]);
77+
if (mention) {
78+
return {
79+
display: `@${mention}`,
80+
type: MentionType.USER_EXIST
81+
};
82+
}
83+
}, [tagUserName, tagRoleName, tagUserId, tagRoleId, mention]);
6084

6185
const currentDirectId = useSelector(selectDmGroupCurrentId);
6286
const isDM = Boolean(mode && [ChannelStreamMode.STREAM_MODE_DM, ChannelStreamMode.STREAM_MODE_GROUP].includes(mode));
@@ -75,6 +99,7 @@ const MentionUser = ({ tagUserName, mode, isJumMessageEnabled, isTokenClickAble,
7599
isDm={isDM}
76100
positionShortUser={positionShortUser}
77101
onClose={closeProfileItem}
102+
username={mention}
78103
/>
79104
);
80105
}, [positionShortUser]);
@@ -136,7 +161,8 @@ const MentionUser = ({ tagUserName, mode, isJumMessageEnabled, isTokenClickAble,
136161

137162
export default memo(MentionUser);
138163

139-
const UserProfilePopup = ({ userID, channelId, mode, isDm, positionShortUser, onClose, rootRef }: UserProfilePopupProps) => {
164+
const UserProfilePopup = ({ username, userID, channelId, mode, isDm, positionShortUser, onClose, rootRef }: UserProfilePopupProps) => {
165+
const getUserByUsername = useAppSelector((state) => selectMemberByUsername(state, channelId ?? '', username ?? ''));
140166
const getUserByUserId = useAppSelector((state) =>
141167
selectChannelMemberByUserIds(
142168
state,
@@ -145,17 +171,22 @@ const UserProfilePopup = ({ userID, channelId, mode, isDm, positionShortUser, on
145171
mode === ChannelStreamMode.STREAM_MODE_CHANNEL || mode === ChannelStreamMode.STREAM_MODE_THREAD ? '' : '1'
146172
)
147173
)[0];
174+
const userGetByNameOrId = useMemo(() => {
175+
return getUserByUserId || getUserByUsername;
176+
}, [getUserByUserId, getUserByUsername]);
177+
const userId = userGetByNameOrId.id;
178+
148179
const currentChannel = useSelector(selectCurrentChannel);
149180
const positionStyle = currentChannel?.type === ChannelType.CHANNEL_TYPE_STREAMING ? { right: `120px` } : { left: `${positionShortUser?.left}px` };
150181
const prioritizeName = getNameForPrioritize(
151-
getUserByUserId.clan_nick ?? '',
152-
getUserByUserId.user?.display_name ?? '',
153-
getUserByUserId.user?.username ?? ''
182+
userGetByNameOrId.clan_nick ?? '',
183+
userGetByNameOrId.user?.display_name ?? '',
184+
userGetByNameOrId.user?.username ?? ''
154185
);
155-
const prioritizeAvt = getUserByUserId.clan_avatar ? getUserByUserId.clan_avatar : getUserByUserId.user?.avatar_url;
186+
const prioritizeAvt = userGetByNameOrId.clan_avatar ? userGetByNameOrId.clan_avatar : userGetByNameOrId.user?.avatar_url;
156187

157188
const updatedUserByUserId = {
158-
...getUserByUserId,
189+
...userGetByNameOrId,
159190
prioritizeName,
160191
prioritizeAvt
161192
};
@@ -170,7 +201,7 @@ const UserProfilePopup = ({ userID, channelId, mode, isDm, positionShortUser, on
170201
>
171202
<ModalUserProfile
172203
onClose={onClose}
173-
userID={userID}
204+
userID={userId}
174205
classBanner="rounded-tl-lg rounded-tr-lg h-[105px]"
175206
mode={mode}
176207
positionType={''}

libs/components/src/lib/components/MessageActionsPanel/components/MessageSelect.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const MessageSelect: React.FC<MessageSelectProps> = ({ select, messageId,
6363
id: buttonId,
6464
value: option.value
6565
},
66-
multiple: checkMultipleSelect
66+
multiple: true
6767
})
6868
);
6969
return;
@@ -75,7 +75,8 @@ export const MessageSelect: React.FC<MessageSelectProps> = ({ select, messageId,
7575
id: buttonId,
7676
value: option.value
7777
},
78-
multiple: checkMultipleSelect
78+
multiple: true,
79+
onlyChooseOne: checkMultipleSelect
7980
})
8081
);
8182
};
@@ -107,7 +108,7 @@ export const MessageSelect: React.FC<MessageSelectProps> = ({ select, messageId,
107108
id: buttonId,
108109
value: option.value
109110
},
110-
multiple: checkMultipleSelect
111+
multiple: true
111112
})
112113
);
113114
};

libs/components/src/lib/components/MessageWithUser/MessageLine.tsx

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export interface ElementToken {
9292
channelid?: string;
9393
emojiid?: string;
9494
type?: EBacktickType;
95+
username?: string;
9596
}
9697

9798
const RenderContent = memo(
@@ -150,7 +151,10 @@ const RenderContent = memo(
150151
channelHastagId={`<#${element.channelid}>`}
151152
/>
152153
);
153-
} else if (element.kindOf === ETokenMessage.MENTIONS && element.user_id) {
154+
} else if (
155+
(element.kindOf === ETokenMessage.MENTIONS && element.user_id) ||
156+
(element.kindOf === ETokenMessage.MENTIONS && element.username)
157+
) {
154158
formattedContent.push(
155159
<MentionContent
156160
key={`mentionUser-${s}-${messsageId}`}
@@ -161,6 +165,7 @@ const RenderContent = memo(
161165
mode={mode}
162166
index={index}
163167
s={s}
168+
mention={element.username}
164169
/>
165170
);
166171
} else if (element.kindOf === ETokenMessage.MENTIONS && element.role_id) {
@@ -372,35 +377,39 @@ interface MentionContentProps {
372377
mode: number;
373378
index: number;
374379
s: number;
380+
mention?: string;
375381
}
376382

377-
export const MentionContent = memo(({ element, contentInElement, isTokenClickAble, isJumMessageEnabled, mode, index, s }: MentionContentProps) => {
378-
const { allUserIdsInChannel } = useMessageContextMenu();
379-
let isValidMention = false;
383+
export const MentionContent = memo(
384+
({ mention, element, contentInElement, isTokenClickAble, isJumMessageEnabled, mode, index, s }: MentionContentProps) => {
385+
const { allUserIdsInChannel } = useMessageContextMenu();
386+
let isValidMention = false;
387+
388+
if (allUserIdsInChannel && allUserIdsInChannel?.length > 0) {
389+
if (typeof allUserIdsInChannel?.[0] === 'string') {
390+
isValidMention = (allUserIdsInChannel as string[])?.includes(element.user_id ?? '') || contentInElement === '@here';
391+
} else {
392+
isValidMention =
393+
(allUserIdsInChannel as ChannelMembersEntity[])?.some((member) => member.id === element.user_id) || contentInElement === '@here';
394+
}
395+
}
380396

381-
if (allUserIdsInChannel && allUserIdsInChannel?.length > 0) {
382-
if (typeof allUserIdsInChannel?.[0] === 'string') {
383-
isValidMention = (allUserIdsInChannel as string[])?.includes(element.user_id ?? '') || contentInElement === '@here';
384-
} else {
385-
isValidMention =
386-
(allUserIdsInChannel as ChannelMembersEntity[])?.some((member) => member.id === element.user_id) || contentInElement === '@here';
397+
if (isValidMention || mention) {
398+
return (
399+
<MentionUser
400+
isTokenClickAble={isTokenClickAble}
401+
isJumMessageEnabled={isJumMessageEnabled}
402+
tagUserName={contentInElement ?? ''}
403+
tagUserId={element.user_id}
404+
mode={mode}
405+
mention={mention}
406+
/>
407+
);
387408
}
388-
}
389409

390-
if (isValidMention) {
391-
return (
392-
<MentionUser
393-
isTokenClickAble={isTokenClickAble}
394-
isJumMessageEnabled={isJumMessageEnabled}
395-
tagUserName={contentInElement ?? ''}
396-
tagUserId={element.user_id}
397-
mode={mode}
398-
/>
399-
);
410+
return <PlainText isSearchMessage={false} text={contentInElement ?? ''} />;
400411
}
401-
402-
return <PlainText isSearchMessage={false} text={contentInElement ?? ''} />;
403-
});
412+
);
404413

405414
interface RoleMentionContentProps {
406415
element: ElementToken;

libs/core/src/lib/chat/contexts/ChatContext.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
reactionActions,
4343
rolesClanActions,
4444
selectAllTextChannel,
45+
selectAllUserClans,
4546
selectChannelsByClanId,
4647
selectClanView,
4748
selectCurrentChannel,
@@ -79,7 +80,8 @@ import {
7980
TIME_OFFSET,
8081
TOKEN_TO_AMOUNT,
8182
ThreadStatus,
82-
TypeMessage
83+
TypeMessage,
84+
electronBridge
8385
} from '@mezon/utils';
8486
import isElectron from 'is-electron';
8587
import {
@@ -1081,12 +1083,38 @@ const ChatContextProvider: React.FC<ChatContextProviderProps> = ({ children }) =
10811083
const oncoffeegiven = useCallback((coffeeEvent: ApiGiveCoffeeEvent) => {
10821084
const isReceiverGiveCoffee = coffeeEvent.receiver_id === userId;
10831085
const isSenderGiveCoffee = coffeeEvent.sender_id === userId;
1086+
10841087
const updateAmount = isReceiverGiveCoffee
10851088
? AMOUNT_TOKEN.TEN_TOKENS * TOKEN_TO_AMOUNT.ONE_THOUNSAND
10861089
: isSenderGiveCoffee
10871090
? -AMOUNT_TOKEN.TEN_TOKENS * TOKEN_TO_AMOUNT.ONE_THOUNSAND
10881091
: 0;
10891092
dispatch(accountActions.updateWalletByAction((currentValue) => currentValue + updateAmount));
1093+
if (isReceiverGiveCoffee && isElectron()) {
1094+
const senderToken = coffeeEvent.sender_id;
1095+
const allMembersClan = selectAllUserClans(store.getState() as RootState);
1096+
let member = null;
1097+
for (const m of allMembersClan) {
1098+
if (m.id === senderToken) {
1099+
member = m;
1100+
break;
1101+
}
1102+
}
1103+
if (!member) return;
1104+
const prioritizedName = member.clan_nick || member.user?.display_name || member.user?.username;
1105+
const prioritizedAvatar = member.clan_avatar || member.user?.avatar_url;
1106+
1107+
const title = 'Token Received:';
1108+
const body = `+${(AMOUNT_TOKEN.TEN_TOKENS * TOKEN_TO_AMOUNT.ONE_THOUNSAND).toLocaleString('vi-VN')}vnđ from ${prioritizedName}`;
1109+
1110+
electronBridge.pushNotification(title, {
1111+
body: body,
1112+
icon: prioritizedAvatar,
1113+
data: {
1114+
link: ''
1115+
}
1116+
});
1117+
}
10901118
}, []);
10911119

10921120
const onroleevent = useCallback(

libs/store/src/lib/channelmembers/channel.members.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,39 @@ export const selectAllChannelMembers = createSelector(
546546
}
547547
);
548548

549+
export const selectMemberByUsername = createSelector(
550+
[
551+
selectMemberIdsByChannelId,
552+
getUsersClanState,
553+
(state: RootState, channelId: string, username: string) => {
554+
const currentClanId = state.clans?.currentClanId;
555+
const channel = state.channels?.byClans[currentClanId as string]?.entities?.entities?.[channelId];
556+
const isPrivate = channel?.channel_private;
557+
const parentId = channel?.parrent_id;
558+
return `${channelId},${isPrivate},${parentId},${username}`;
559+
}
560+
],
561+
(channelMembers, usersClanState, payload) => {
562+
const [channelId, isPrivate, parentId, username] = payload.split(',');
563+
if (!usersClanState?.ids?.length) return null;
564+
const members = isPrivate === '1' || (parentId !== '0' && parentId !== '') ? { ids: channelMembers } : usersClanState;
565+
if (!members?.ids) return null;
566+
const ids = members.ids || [];
567+
for (const id of ids) {
568+
const member = {
569+
...usersClanState.entities[id],
570+
channelId,
571+
userChannelId: channelId
572+
};
573+
if (member.user?.username === username) {
574+
return member;
575+
}
576+
}
577+
578+
return null;
579+
}
580+
);
581+
549582
export const selectAllChannelMemberIds = createSelector(
550583
[
551584
getChannelMembersState,

0 commit comments

Comments
 (0)