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