@esvndev/es-react-template-chat 0.0.89 → 0.0.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +266 -381
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +266 -381
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -72041,7 +72041,7 @@ const ChatLog = (props) => {
|
|
|
72041
72041
|
const { typeChat, contactId, chatRoomId, active, messageByGroup, pinnedMessages, setScroll, checkScroll, pinMessageChatRoom, deleteMessageApi, recallMessageApi, get_message_by_group_cursor_api, getPinMessageChatRoomApi, deletePinMessage,
|
|
72042
72042
|
//updateGroupTagApi,
|
|
72043
72043
|
createReminderApi, senMessageApi, typingUsers } = useChat();
|
|
72044
|
-
useAppSelector((state) => state.hubNotification);
|
|
72044
|
+
const { connection } = useAppSelector((state) => state.hubNotification);
|
|
72045
72045
|
const [dynamicMenuItems, setDynamicMenuItems] = useState([]);
|
|
72046
72046
|
useEffect(() => {
|
|
72047
72047
|
const fetchFormConfig = async () => {
|
|
@@ -72082,38 +72082,68 @@ const ChatLog = (props) => {
|
|
|
72082
72082
|
], [dynamicMenuItems]);
|
|
72083
72083
|
// Menu items cho Hành chính (chỉ administrative)
|
|
72084
72084
|
useMemo(() => ADMINISTRATIVE_ITEMS, []);
|
|
72085
|
-
useRef(false);
|
|
72086
|
-
useRef(null);
|
|
72087
|
-
useRef(null);
|
|
72085
|
+
const isTypingRef = useRef(false);
|
|
72086
|
+
const typingTimeoutRef = useRef(null);
|
|
72088
72087
|
useRef(null);
|
|
72089
72088
|
useRef(null);
|
|
72089
|
+
const inputContainer = useRef(null);
|
|
72090
72090
|
const containerChatRef = useRef(null);
|
|
72091
72091
|
const { connectHub, dataInfo, dataProfile, handleUser, handleUserSidebarRight, handleSidebar, handleSidebarRight, userSidebarLeft, dataHistory, chatGetType, approveUpdateStatus, handleModalAdministrative, setDataItem, handleModalAddUserGroup, handleModalGroup, typeOpenModalAdd, setTypeOpenModalAdd, unpinMessage, getPinnedMessages } = props;
|
|
72092
72092
|
const groupChatUsers = dataHistory?.find((dt) => dt.id === active);
|
|
72093
72093
|
//const dataInfoAvatar = dataInfo && dataInfo.avatar ? dataInfo.avatar : DEFAULT_AVATAR
|
|
72094
|
-
useState([]);
|
|
72095
|
-
useState(false);
|
|
72094
|
+
const [imgCopy, setImgCopy] = useState([]);
|
|
72095
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
72096
72096
|
const [openModalPreview, setOpenModalPreview] = useState(false);
|
|
72097
72097
|
useState(false);
|
|
72098
72098
|
useState(false);
|
|
72099
72099
|
useState(false);
|
|
72100
72100
|
useState('');
|
|
72101
72101
|
useState(null);
|
|
72102
|
-
useState(null);
|
|
72103
|
-
useState(null);
|
|
72104
|
-
useState({ x: 0, y: 0 });
|
|
72105
|
-
useState(undefined);
|
|
72106
|
-
useState(undefined);
|
|
72102
|
+
const [currentMessage, setCurrentMessage] = useState(null);
|
|
72103
|
+
const [replyMessage, setReplyMessage] = useState(null);
|
|
72104
|
+
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
72105
|
+
const [listContextShow, setListContextShow] = useState(undefined);
|
|
72106
|
+
const [listContextHide, setListContextHide] = useState(undefined);
|
|
72107
72107
|
const [selectedMessage, setSelectedMessage] = useState(null);
|
|
72108
|
-
useState(false);
|
|
72109
|
-
useState(true);
|
|
72110
|
-
useRef(0);
|
|
72108
|
+
const [isMultiLine, setIsMultiLine] = useState(false);
|
|
72109
|
+
const [isAtBottom, setIsAtBottom] = useState(true);
|
|
72110
|
+
const prevListLength = useRef(0);
|
|
72111
72111
|
useState(0);
|
|
72112
72112
|
useState(true);
|
|
72113
|
-
useState(new Set());
|
|
72114
|
-
useState(null);
|
|
72113
|
+
const [expandedMessages, setExpandedMessages] = useState(new Set());
|
|
72114
|
+
const [clickedImageFile, setClickedImageFile] = useState(null);
|
|
72115
72115
|
useState(false);
|
|
72116
72116
|
useState(new Set());
|
|
72117
|
+
const BASE_CONTEXT_ITEMS = [
|
|
72118
|
+
"reply", "share", "pin", "bookmark",
|
|
72119
|
+
"selectMultiMessage", "detail", "other", "recall", "delete"
|
|
72120
|
+
];
|
|
72121
|
+
const CONTEXT_CONFIG = {
|
|
72122
|
+
selection: {
|
|
72123
|
+
show: ["copyRangeText", ...BASE_CONTEXT_ITEMS, "save"],
|
|
72124
|
+
hide: ["copyText", "save", "copyImage"]
|
|
72125
|
+
},
|
|
72126
|
+
image: {
|
|
72127
|
+
show: ["copyImage", ...BASE_CONTEXT_ITEMS, "save"],
|
|
72128
|
+
hide: ["copyText", "copyRangeText"]
|
|
72129
|
+
},
|
|
72130
|
+
file: {
|
|
72131
|
+
show: [...BASE_CONTEXT_ITEMS, "save"],
|
|
72132
|
+
hide: ["copyText", "copyRangeText", "copyImage"]
|
|
72133
|
+
},
|
|
72134
|
+
text: {
|
|
72135
|
+
show: ["copyText", ...BASE_CONTEXT_ITEMS],
|
|
72136
|
+
hide: ["copyRangeText", "save", "copyImage"]
|
|
72137
|
+
},
|
|
72138
|
+
voucher: {
|
|
72139
|
+
show: ["copyText", ...BASE_CONTEXT_ITEMS],
|
|
72140
|
+
hide: ["copyRangeText", "save", "copyImage"]
|
|
72141
|
+
},
|
|
72142
|
+
default: {
|
|
72143
|
+
show: ["copyText", ...BASE_CONTEXT_ITEMS],
|
|
72144
|
+
hide: ["copyRangeText", "save", "copyImage"]
|
|
72145
|
+
}
|
|
72146
|
+
};
|
|
72117
72147
|
useState(true);
|
|
72118
72148
|
const scrollToBottom = () => {
|
|
72119
72149
|
const messagesEndEle = document.getElementById('messagesEnd');
|
|
@@ -72125,7 +72155,7 @@ const ChatLog = (props) => {
|
|
|
72125
72155
|
scrollToBottom();
|
|
72126
72156
|
}
|
|
72127
72157
|
}, [messageByGroup, checkScroll]);
|
|
72128
|
-
useMemo(() => {
|
|
72158
|
+
const mentionItems = useMemo(() => {
|
|
72129
72159
|
if (!groupChatUsers) {
|
|
72130
72160
|
return [];
|
|
72131
72161
|
}
|
|
@@ -72143,375 +72173,230 @@ const ChatLog = (props) => {
|
|
|
72143
72173
|
});
|
|
72144
72174
|
return [{ id: "all", name: "All" }, ...mappedUsers];
|
|
72145
72175
|
}, [groupChatUsers]);
|
|
72146
|
-
useCallback((mes) => {
|
|
72176
|
+
const handlePreview = useCallback((mes) => {
|
|
72147
72177
|
setSelectedMessage(mes);
|
|
72148
72178
|
setOpenModalPreview(true);
|
|
72149
72179
|
}, []);
|
|
72150
72180
|
useState(false);
|
|
72151
72181
|
useDispatch();
|
|
72152
|
-
|
|
72153
|
-
|
|
72154
|
-
|
|
72155
|
-
|
|
72156
|
-
|
|
72157
|
-
|
|
72158
|
-
|
|
72159
|
-
|
|
72160
|
-
|
|
72161
|
-
|
|
72162
|
-
|
|
72163
|
-
|
|
72164
|
-
|
|
72165
|
-
|
|
72166
|
-
|
|
72167
|
-
|
|
72168
|
-
|
|
72169
|
-
|
|
72170
|
-
|
|
72171
|
-
|
|
72172
|
-
|
|
72173
|
-
|
|
72174
|
-
|
|
72175
|
-
|
|
72176
|
-
|
|
72177
|
-
|
|
72178
|
-
|
|
72179
|
-
|
|
72180
|
-
|
|
72181
|
-
|
|
72182
|
-
|
|
72183
|
-
|
|
72184
|
-
|
|
72185
|
-
|
|
72186
|
-
|
|
72187
|
-
|
|
72188
|
-
|
|
72189
|
-
|
|
72190
|
-
|
|
72191
|
-
|
|
72192
|
-
|
|
72193
|
-
|
|
72194
|
-
|
|
72195
|
-
|
|
72196
|
-
|
|
72197
|
-
|
|
72198
|
-
|
|
72199
|
-
|
|
72200
|
-
|
|
72201
|
-
|
|
72202
|
-
|
|
72203
|
-
|
|
72204
|
-
|
|
72205
|
-
|
|
72206
|
-
|
|
72207
|
-
|
|
72208
|
-
|
|
72209
|
-
|
|
72210
|
-
|
|
72211
|
-
|
|
72212
|
-
|
|
72213
|
-
|
|
72214
|
-
|
|
72215
|
-
|
|
72216
|
-
|
|
72217
|
-
|
|
72218
|
-
|
|
72219
|
-
|
|
72220
|
-
|
|
72221
|
-
|
|
72222
|
-
//
|
|
72223
|
-
|
|
72224
|
-
|
|
72225
|
-
|
|
72226
|
-
|
|
72227
|
-
|
|
72228
|
-
|
|
72229
|
-
|
|
72230
|
-
|
|
72231
|
-
|
|
72232
|
-
|
|
72233
|
-
|
|
72234
|
-
|
|
72235
|
-
|
|
72236
|
-
|
|
72237
|
-
|
|
72238
|
-
|
|
72239
|
-
|
|
72240
|
-
|
|
72241
|
-
|
|
72242
|
-
|
|
72243
|
-
|
|
72244
|
-
|
|
72245
|
-
|
|
72246
|
-
|
|
72247
|
-
|
|
72248
|
-
|
|
72249
|
-
|
|
72250
|
-
|
|
72251
|
-
|
|
72252
|
-
|
|
72253
|
-
|
|
72254
|
-
|
|
72255
|
-
|
|
72256
|
-
|
|
72257
|
-
|
|
72258
|
-
|
|
72259
|
-
|
|
72260
|
-
|
|
72261
|
-
|
|
72262
|
-
|
|
72263
|
-
|
|
72264
|
-
|
|
72265
|
-
|
|
72266
|
-
|
|
72267
|
-
|
|
72268
|
-
|
|
72269
|
-
|
|
72270
|
-
|
|
72271
|
-
|
|
72272
|
-
|
|
72273
|
-
|
|
72274
|
-
|
|
72275
|
-
|
|
72276
|
-
|
|
72277
|
-
|
|
72278
|
-
|
|
72279
|
-
|
|
72280
|
-
|
|
72281
|
-
|
|
72282
|
-
|
|
72283
|
-
|
|
72284
|
-
|
|
72285
|
-
|
|
72286
|
-
|
|
72287
|
-
|
|
72288
|
-
|
|
72289
|
-
|
|
72290
|
-
|
|
72291
|
-
|
|
72292
|
-
|
|
72293
|
-
|
|
72294
|
-
|
|
72295
|
-
|
|
72296
|
-
|
|
72297
|
-
|
|
72298
|
-
|
|
72299
|
-
|
|
72300
|
-
|
|
72301
|
-
|
|
72302
|
-
|
|
72303
|
-
|
|
72304
|
-
|
|
72305
|
-
|
|
72306
|
-
|
|
72307
|
-
|
|
72308
|
-
|
|
72309
|
-
|
|
72310
|
-
|
|
72311
|
-
|
|
72312
|
-
|
|
72313
|
-
|
|
72314
|
-
|
|
72315
|
-
|
|
72316
|
-
|
|
72317
|
-
|
|
72318
|
-
|
|
72319
|
-
|
|
72320
|
-
|
|
72321
|
-
|
|
72322
|
-
|
|
72323
|
-
|
|
72324
|
-
|
|
72325
|
-
|
|
72326
|
-
|
|
72327
|
-
|
|
72328
|
-
|
|
72329
|
-
|
|
72330
|
-
|
|
72331
|
-
|
|
72332
|
-
|
|
72333
|
-
|
|
72334
|
-
|
|
72335
|
-
|
|
72336
|
-
|
|
72337
|
-
|
|
72338
|
-
|
|
72339
|
-
|
|
72340
|
-
|
|
72341
|
-
|
|
72342
|
-
|
|
72343
|
-
|
|
72344
|
-
|
|
72345
|
-
|
|
72346
|
-
|
|
72347
|
-
|
|
72348
|
-
|
|
72349
|
-
|
|
72350
|
-
|
|
72351
|
-
|
|
72352
|
-
|
|
72353
|
-
|
|
72354
|
-
|
|
72355
|
-
|
|
72356
|
-
|
|
72357
|
-
|
|
72358
|
-
|
|
72359
|
-
|
|
72360
|
-
|
|
72361
|
-
|
|
72362
|
-
|
|
72363
|
-
|
|
72364
|
-
|
|
72365
|
-
|
|
72366
|
-
|
|
72367
|
-
|
|
72368
|
-
|
|
72369
|
-
|
|
72370
|
-
// }
|
|
72371
|
-
// setExpandedMessages(newExpanded)
|
|
72372
|
-
// }
|
|
72373
|
-
// const formatMentionsReact = (text: string, mentions: any[], messageId: string) => {
|
|
72374
|
-
// if (!text || !mentions || mentions.length === 0) { return text }
|
|
72375
|
-
// const maxLength = 200
|
|
72376
|
-
// const isExpanded = expandedMessages.has(messageId)
|
|
72377
|
-
// let displayText = text
|
|
72378
|
-
// let isTruncated = false
|
|
72379
|
-
// if (!isExpanded && text.length > maxLength) {
|
|
72380
|
-
// displayText = text.substring(0, maxLength)
|
|
72381
|
-
// isTruncated = true
|
|
72382
|
-
// }
|
|
72383
|
-
// // Chỉ highlight những mention có trong danh sách
|
|
72384
|
-
// let result: any = displayText
|
|
72385
|
-
// // Hàm helper để xử lý mention trong cả string và array
|
|
72386
|
-
// const processMention = (text: string, mention: any): any => {
|
|
72387
|
-
// const escapedName = mention?.name?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
72388
|
-
// const mentionRegex = new RegExp(`@${escapedName}(?=\\s|$|[.,;:!?()[\\]{}'"\`~@])`, 'g')
|
|
72389
|
-
// const parts = text.split(mentionRegex)
|
|
72390
|
-
// const matches = text.match(mentionRegex) || []
|
|
72391
|
-
// if (matches.length === 0) {
|
|
72392
|
-
// return text
|
|
72393
|
-
// }
|
|
72394
|
-
// const newParts: any[] = []
|
|
72395
|
-
// parts.forEach((part: any, index: any) => {
|
|
72396
|
-
// newParts.push(part)
|
|
72397
|
-
// if (matches[index]) {
|
|
72398
|
-
// newParts.push(
|
|
72399
|
-
// <span key={`mention-${messageId}-${mention.id || mention.name}-${index}`} className="chat-mention">
|
|
72400
|
-
// {matches[index]}
|
|
72401
|
-
// </span>
|
|
72402
|
-
// )
|
|
72403
|
-
// }
|
|
72404
|
-
// })
|
|
72405
|
-
// return newParts
|
|
72406
|
-
// }
|
|
72407
|
-
// mentions.forEach((mention: any) => {
|
|
72408
|
-
// if (typeof result === 'string') {
|
|
72409
|
-
// result = processMention(result, mention)
|
|
72410
|
-
// } else if (Array.isArray(result)) {
|
|
72411
|
-
// // Xử lý từng phần tử trong array
|
|
72412
|
-
// const processedArray: any[] = []
|
|
72413
|
-
// result.forEach((item: any) => {
|
|
72414
|
-
// if (typeof item === 'string') {
|
|
72415
|
-
// const processed = processMention(item, mention)
|
|
72416
|
-
// if (Array.isArray(processed)) {
|
|
72417
|
-
// processedArray.push(...processed)
|
|
72418
|
-
// } else {
|
|
72419
|
-
// processedArray.push(processed)
|
|
72420
|
-
// }
|
|
72421
|
-
// } else {
|
|
72422
|
-
// // Giữ nguyên các React elements đã được xử lý
|
|
72423
|
-
// processedArray.push(item)
|
|
72424
|
-
// }
|
|
72425
|
-
// })
|
|
72426
|
-
// result = processedArray
|
|
72427
|
-
// }
|
|
72428
|
-
// })
|
|
72429
|
-
// // Add expand/collapse functionality
|
|
72430
|
-
// if (isTruncated || (isExpanded && text.length > maxLength)) {
|
|
72431
|
-
// const expandButton = (
|
|
72432
|
-
// <span
|
|
72433
|
-
// key={`expand-${messageId}`}
|
|
72434
|
-
// onClick={() => toggleExpanded(messageId)}
|
|
72435
|
-
// style={{
|
|
72436
|
-
// color: '#006edc',
|
|
72437
|
-
// cursor: 'pointer',
|
|
72438
|
-
// fontWeight: 500,
|
|
72439
|
-
// marginLeft: 5
|
|
72440
|
-
// }}
|
|
72441
|
-
// >
|
|
72442
|
-
// {isExpanded ? ' Thu gọn' : '... Mở rộng'}
|
|
72443
|
-
// </span>
|
|
72444
|
-
// )
|
|
72445
|
-
// if (Array.isArray(result)) {
|
|
72446
|
-
// result.push(expandButton)
|
|
72447
|
-
// } else {
|
|
72448
|
-
// result = [result, expandButton]
|
|
72449
|
-
// }
|
|
72450
|
-
// }
|
|
72451
|
-
// return result
|
|
72452
|
-
// }
|
|
72453
|
-
// return (
|
|
72454
|
-
// <>
|
|
72455
|
-
// <div>
|
|
72456
|
-
// <div>
|
|
72457
|
-
// {chat.path && chat.path.length === 1 && (
|
|
72458
|
-
// <div className="image-container">
|
|
72459
|
-
// {img && <img src={img} alt="" />}
|
|
72460
|
-
// </div>
|
|
72461
|
-
// )}
|
|
72462
|
-
// {isValidUrl(chat.msg) && renderLinkPreview(chat.msg)}
|
|
72463
|
-
// {chat.msg && !isValidUrl(chat.msg) ? (
|
|
72464
|
-
// <div>{formatMentionsReact(chat.msg, mentionItems, chat.id)}</div>
|
|
72465
|
-
// ) : (
|
|
72466
|
-
// <></>
|
|
72467
|
-
// )}
|
|
72468
|
-
// {chat.path && chat.path.length > 1 && (
|
|
72469
|
-
// <div className="group-image">
|
|
72470
|
-
// {chat.path.map((it: any, index: any) => {
|
|
72471
|
-
// return (
|
|
72472
|
-
// <div
|
|
72473
|
-
// key={index}
|
|
72474
|
-
// className="group-image-item image-container"
|
|
72475
|
-
// >
|
|
72476
|
-
// <img
|
|
72477
|
-
// style={{ maxWidth: "100%", maxHeight: 360 }}
|
|
72478
|
-
// src={`${CDN_URL_VIEW}/${it.path.trim()}`}
|
|
72479
|
-
// onClick={() => handlePreview(it)}
|
|
72480
|
-
// alt=""
|
|
72481
|
-
// />
|
|
72482
|
-
// </div>
|
|
72483
|
-
// )
|
|
72484
|
-
// })}
|
|
72485
|
-
// </div>
|
|
72486
|
-
// )}
|
|
72487
|
-
// <div className="" style={{ fontSize: "12px", color: "#476285" }}>
|
|
72488
|
-
// {moment(chat.time).format("HH:mm")}
|
|
72489
|
-
// </div>
|
|
72490
|
-
// </div>
|
|
72491
|
-
// </div>
|
|
72492
|
-
// </>
|
|
72493
|
-
// )
|
|
72494
|
-
// }, [expandedMessages, handlePreview, mentionItems])
|
|
72495
|
-
// const getLinkPreviewData = (urlString: string) => {
|
|
72496
|
-
// try {
|
|
72497
|
-
// const hasProtocol = /^https?:\/\//i.test(urlString)
|
|
72498
|
-
// const href = hasProtocol ? urlString : `https://${urlString}`
|
|
72499
|
-
// const url = new URL(href)
|
|
72500
|
-
// const displayUrl =
|
|
72501
|
-
// urlString.length > 80 ? `${urlString.slice(0, 77)}...` : urlString
|
|
72502
|
-
// return {
|
|
72503
|
-
// href,
|
|
72504
|
-
// displayUrl,
|
|
72505
|
-
// host: url.host
|
|
72506
|
-
// }
|
|
72507
|
-
// } catch (e) {
|
|
72508
|
-
// return {
|
|
72509
|
-
// href: urlString,
|
|
72510
|
-
// displayUrl: urlString,
|
|
72511
|
-
// host: ''
|
|
72512
|
-
// }
|
|
72513
|
-
// }
|
|
72514
|
-
// }
|
|
72182
|
+
useCallback((idx) => {
|
|
72183
|
+
const newArr = [...imgCopy];
|
|
72184
|
+
newArr.splice(idx, 1);
|
|
72185
|
+
setImgCopy(newArr);
|
|
72186
|
+
}, [imgCopy]);
|
|
72187
|
+
useCallback((e, chatMessage) => {
|
|
72188
|
+
const selection = window.document.getSelection();
|
|
72189
|
+
setIsOpen(true);
|
|
72190
|
+
setPosition({ x: e.clientX, y: e.clientY });
|
|
72191
|
+
if (e.target) {
|
|
72192
|
+
setCurrentMessage(chatMessage);
|
|
72193
|
+
}
|
|
72194
|
+
// Detect ảnh được click từ data attribute
|
|
72195
|
+
const fileIndex = e.target?.dataset?.fileIndex;
|
|
72196
|
+
if (fileIndex !== undefined && chatMessage?.path) {
|
|
72197
|
+
setClickedImageFile(chatMessage.path[parseInt(fileIndex)]);
|
|
72198
|
+
}
|
|
72199
|
+
else {
|
|
72200
|
+
setClickedImageFile(null);
|
|
72201
|
+
}
|
|
72202
|
+
e.preventDefault();
|
|
72203
|
+
const contextType = selection.toString() ? 'selection' : chatMessage?.type ? chatMessage.type : 'default';
|
|
72204
|
+
const config = CONTEXT_CONFIG[contextType];
|
|
72205
|
+
setListContextShow({ list: config.show, type: "SHOW" });
|
|
72206
|
+
setListContextHide({ list: config.hide, type: "HIDE" });
|
|
72207
|
+
}, []);
|
|
72208
|
+
const handleTypingStart = () => {
|
|
72209
|
+
if (!isTypingRef.current && connection && chatRoomId) {
|
|
72210
|
+
connection.invoke('StartTyping', chatRoomId).catch(console.error);
|
|
72211
|
+
isTypingRef.current = true;
|
|
72212
|
+
}
|
|
72213
|
+
};
|
|
72214
|
+
const handleTypingStop = () => {
|
|
72215
|
+
if (typingTimeoutRef.current) {
|
|
72216
|
+
clearTimeout(typingTimeoutRef.current);
|
|
72217
|
+
}
|
|
72218
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
72219
|
+
if (isTypingRef.current && connection && chatRoomId) {
|
|
72220
|
+
connection.invoke('StopTyping', chatRoomId).catch(console.error);
|
|
72221
|
+
isTypingRef.current = false;
|
|
72222
|
+
}
|
|
72223
|
+
}, 2000);
|
|
72224
|
+
};
|
|
72225
|
+
useCallback((editorState) => {
|
|
72226
|
+
if (inputContainer &&
|
|
72227
|
+
inputContainer.current &&
|
|
72228
|
+
inputContainer.current.clientHeight > 50) {
|
|
72229
|
+
setIsMultiLine(true);
|
|
72230
|
+
}
|
|
72231
|
+
else {
|
|
72232
|
+
setIsMultiLine(false);
|
|
72233
|
+
}
|
|
72234
|
+
editorState.read(() => {
|
|
72235
|
+
handleTypingStart();
|
|
72236
|
+
handleTypingStop();
|
|
72237
|
+
});
|
|
72238
|
+
}, [inputContainer, connection, chatRoomId]);
|
|
72239
|
+
useEffect(() => {
|
|
72240
|
+
if (active) {
|
|
72241
|
+
setReplyMessage(null);
|
|
72242
|
+
setImgCopy([]);
|
|
72243
|
+
setIsAtBottom(true);
|
|
72244
|
+
prevListLength.current = 0;
|
|
72245
|
+
}
|
|
72246
|
+
}, [
|
|
72247
|
+
active,
|
|
72248
|
+
dataInfo
|
|
72249
|
+
//chatRoomId,
|
|
72250
|
+
//chatGetType
|
|
72251
|
+
]);
|
|
72252
|
+
// Chuyển phòng thì load lại message + pinned messages
|
|
72253
|
+
useEffect(() => {
|
|
72254
|
+
if (!chatRoomId && handleSidebar) {
|
|
72255
|
+
return;
|
|
72256
|
+
}
|
|
72257
|
+
chatGetType(chatRoomId, undefined, "", "", undefined, undefined, 0, 0);
|
|
72258
|
+
if (chatRoomId) {
|
|
72259
|
+
getPinMessageChatRoomApi(chatRoomId);
|
|
72260
|
+
}
|
|
72261
|
+
}, [chatRoomId]);
|
|
72262
|
+
useCallback(async (message) => {
|
|
72263
|
+
const pinId = message?.pinId || message?.id;
|
|
72264
|
+
if (!pinId) {
|
|
72265
|
+
return;
|
|
72266
|
+
}
|
|
72267
|
+
await deletePinMessage(pinId);
|
|
72268
|
+
}, [deletePinMessage, chatRoomId]);
|
|
72269
|
+
useCallback((message) => {
|
|
72270
|
+
if (message?.id) {
|
|
72271
|
+
//setViewingPinnedMessage(message.id)
|
|
72272
|
+
// Tìm message element
|
|
72273
|
+
const element = document.getElementById(`msg-${message.id}`);
|
|
72274
|
+
const chatContainer = document.getElementById('scrollableDivChat');
|
|
72275
|
+
if (element && chatContainer) {
|
|
72276
|
+
// Lấy vị trí của element và container
|
|
72277
|
+
const elementRect = element.getBoundingClientRect();
|
|
72278
|
+
const containerRect = chatContainer.getBoundingClientRect();
|
|
72279
|
+
// Tính toán scroll position để đưa element vào giữa container
|
|
72280
|
+
const scrollTop = chatContainer.scrollTop;
|
|
72281
|
+
const offset = elementRect.top - containerRect.top - (containerRect.height / 2) + (elementRect.height / 2);
|
|
72282
|
+
// Scroll trong container, không scroll toàn page
|
|
72283
|
+
chatContainer.scrollTo({
|
|
72284
|
+
top: scrollTop + offset,
|
|
72285
|
+
behavior: 'smooth'
|
|
72286
|
+
});
|
|
72287
|
+
// Highlight message
|
|
72288
|
+
const originalBg = element.style.backgroundColor;
|
|
72289
|
+
const originalZIndex = element.style.zIndex;
|
|
72290
|
+
element.style.backgroundColor = '#fff3cd';
|
|
72291
|
+
element.style.zIndex = '1000';
|
|
72292
|
+
element.style.position = 'relative';
|
|
72293
|
+
element.style.transition = 'background-color 0.3s';
|
|
72294
|
+
// Auto close sau 500ms
|
|
72295
|
+
setTimeout(() => {
|
|
72296
|
+
element.style.backgroundColor = originalBg || '';
|
|
72297
|
+
element.style.zIndex = originalZIndex || '';
|
|
72298
|
+
//setViewingPinnedMessage(null)
|
|
72299
|
+
}, 500);
|
|
72300
|
+
}
|
|
72301
|
+
else {
|
|
72302
|
+
console.log('Message not found in current view, may need to load more messages');
|
|
72303
|
+
setTimeout(() => {
|
|
72304
|
+
//setViewingPinnedMessage(null)
|
|
72305
|
+
}, 2000);
|
|
72306
|
+
}
|
|
72307
|
+
}
|
|
72308
|
+
}, []);
|
|
72309
|
+
useCallback((chat) => {
|
|
72310
|
+
const isPath = Array.isArray(chat?.path) && typeof chat.path[0]?.path === "string" ? chat.path[0].path.trim() : "";
|
|
72311
|
+
const img = isPath ? `${CDN_URL_VIEW}/${isPath}` : "";
|
|
72312
|
+
const toggleExpanded = (messageId) => {
|
|
72313
|
+
const newExpanded = new Set(expandedMessages);
|
|
72314
|
+
if (newExpanded.has(messageId)) {
|
|
72315
|
+
newExpanded.delete(messageId);
|
|
72316
|
+
}
|
|
72317
|
+
else {
|
|
72318
|
+
newExpanded.add(messageId);
|
|
72319
|
+
}
|
|
72320
|
+
setExpandedMessages(newExpanded);
|
|
72321
|
+
};
|
|
72322
|
+
const formatMentionsReact = (text, mentions, messageId) => {
|
|
72323
|
+
if (!text || !mentions || mentions.length === 0) {
|
|
72324
|
+
return text;
|
|
72325
|
+
}
|
|
72326
|
+
const maxLength = 200;
|
|
72327
|
+
const isExpanded = expandedMessages.has(messageId);
|
|
72328
|
+
let displayText = text;
|
|
72329
|
+
let isTruncated = false;
|
|
72330
|
+
if (!isExpanded && text.length > maxLength) {
|
|
72331
|
+
displayText = text.substring(0, maxLength);
|
|
72332
|
+
isTruncated = true;
|
|
72333
|
+
}
|
|
72334
|
+
// Chỉ highlight những mention có trong danh sách
|
|
72335
|
+
let result = displayText;
|
|
72336
|
+
// Hàm helper để xử lý mention trong cả string và array
|
|
72337
|
+
const processMention = (text, mention) => {
|
|
72338
|
+
const escapedName = mention?.name?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
72339
|
+
const mentionRegex = new RegExp(`@${escapedName}(?=\\s|$|[.,;:!?()[\\]{}'"\`~@])`, 'g');
|
|
72340
|
+
const parts = text.split(mentionRegex);
|
|
72341
|
+
const matches = text.match(mentionRegex) || [];
|
|
72342
|
+
if (matches.length === 0) {
|
|
72343
|
+
return text;
|
|
72344
|
+
}
|
|
72345
|
+
const newParts = [];
|
|
72346
|
+
parts.forEach((part, index) => {
|
|
72347
|
+
newParts.push(part);
|
|
72348
|
+
if (matches[index]) {
|
|
72349
|
+
newParts.push(jsx("span", { className: "chat-mention", children: matches[index] }, `mention-${messageId}-${mention.id || mention.name}-${index}`));
|
|
72350
|
+
}
|
|
72351
|
+
});
|
|
72352
|
+
return newParts;
|
|
72353
|
+
};
|
|
72354
|
+
mentions.forEach((mention) => {
|
|
72355
|
+
if (typeof result === 'string') {
|
|
72356
|
+
result = processMention(result, mention);
|
|
72357
|
+
}
|
|
72358
|
+
else if (Array.isArray(result)) {
|
|
72359
|
+
// Xử lý từng phần tử trong array
|
|
72360
|
+
const processedArray = [];
|
|
72361
|
+
result.forEach((item) => {
|
|
72362
|
+
if (typeof item === 'string') {
|
|
72363
|
+
const processed = processMention(item, mention);
|
|
72364
|
+
if (Array.isArray(processed)) {
|
|
72365
|
+
processedArray.push(...processed);
|
|
72366
|
+
}
|
|
72367
|
+
else {
|
|
72368
|
+
processedArray.push(processed);
|
|
72369
|
+
}
|
|
72370
|
+
}
|
|
72371
|
+
else {
|
|
72372
|
+
// Giữ nguyên các React elements đã được xử lý
|
|
72373
|
+
processedArray.push(item);
|
|
72374
|
+
}
|
|
72375
|
+
});
|
|
72376
|
+
result = processedArray;
|
|
72377
|
+
}
|
|
72378
|
+
});
|
|
72379
|
+
// Add expand/collapse functionality
|
|
72380
|
+
if (isTruncated || (isExpanded && text.length > maxLength)) {
|
|
72381
|
+
const expandButton = (jsx("span", { onClick: () => toggleExpanded(messageId), style: {
|
|
72382
|
+
color: '#006edc',
|
|
72383
|
+
cursor: 'pointer',
|
|
72384
|
+
fontWeight: 500,
|
|
72385
|
+
marginLeft: 5
|
|
72386
|
+
}, children: isExpanded ? ' Thu gọn' : '... Mở rộng' }, `expand-${messageId}`));
|
|
72387
|
+
if (Array.isArray(result)) {
|
|
72388
|
+
result.push(expandButton);
|
|
72389
|
+
}
|
|
72390
|
+
else {
|
|
72391
|
+
result = [result, expandButton];
|
|
72392
|
+
}
|
|
72393
|
+
}
|
|
72394
|
+
return result;
|
|
72395
|
+
};
|
|
72396
|
+
return (jsx(Fragment$1, { children: jsx("div", { children: jsxs("div", { children: [chat.path && chat.path.length === 1 && (jsx("div", { className: "image-container", children: img && jsx("img", { src: img, alt: "" }) })), isValidUrl(chat.msg) && renderLinkPreview(chat.msg), chat.msg && !isValidUrl(chat.msg) ? (jsx("div", { children: formatMentionsReact(chat.msg, mentionItems, chat.id) })) : (jsx(Fragment$1, {})), chat.path && chat.path.length > 1 && (jsx("div", { className: "group-image", children: chat.path.map((it, index) => {
|
|
72397
|
+
return (jsx("div", { className: "group-image-item image-container", children: jsx("img", { style: { maxWidth: "100%", maxHeight: 360 }, src: `${CDN_URL_VIEW}/${it.path.trim()}`, onClick: () => handlePreview(it), alt: "" }) }, index));
|
|
72398
|
+
}) })), jsx("div", { className: "", style: { fontSize: "12px", color: "#476285" }, children: moment(chat.time).format("HH:mm") })] }) }) }));
|
|
72399
|
+
}, [expandedMessages, handlePreview, mentionItems]);
|
|
72515
72400
|
// const renderLinkPreview = (urlString: string) => {
|
|
72516
72401
|
// const { href, displayUrl, host } = getLinkPreviewData(urlString)
|
|
72517
72402
|
// return (
|