@esvndev/es-react-template-chat 0.0.88 → 0.0.90

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.mjs CHANGED
@@ -17,9 +17,9 @@ import { isNullOrUndefined as isNullOrUndefined$2 } from '@src/utility/hooks/isN
17
17
  import avatarDefault from '@core/assets/images/avatars/avatar-blank.png';
18
18
  import '@draft-js-plugins/mention/lib/plugin.css';
19
19
  import '@draft-js-plugins/emoji/lib/plugin.css';
20
+ import { useDispatch } from 'react-redux';
20
21
  import { useAppDispatch as useAppDispatch$1, useAppSelector as useAppSelector$1 } from '@store/configureStore';
21
22
  import { useLocation } from 'react-router-dom';
22
- import { useDispatch } from 'react-redux';
23
23
 
24
24
  var instances = 'ej2_instances';
25
25
  var uid = 0;
@@ -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,44 +72082,73 @@ 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);
72096
- useState(false);
72094
+ const [imgCopy, setImgCopy] = useState([]);
72095
+ const [isOpen, setIsOpen] = useState(false);
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);
72107
- useState(null);
72108
- useState(false);
72109
- useState(true);
72110
- useRef(0);
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
+ const [selectedMessage, setSelectedMessage] = useState(null);
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
72113
  useState(new Set());
72114
- useState(null);
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');
72120
72150
  messagesEndEle?.scrollIntoView({ block: 'end', behavior: "instant" });
72121
72151
  };
72122
- //từ đây
72123
72152
  // Load initial messages
72124
72153
  useEffect(() => {
72125
72154
  if (!checkScroll) {
@@ -72144,340 +72173,139 @@ const ChatLog = (props) => {
72144
72173
  });
72145
72174
  return [{ id: "all", name: "All" }, ...mappedUsers];
72146
72175
  }, [groupChatUsers]);
72147
- // const handlePreview = useCallback((mes: any) => {
72148
- // setSelectedMessage(mes)
72149
- // setOpenModalPreview(true)
72150
- // }, [])
72151
- // const [isFetching, setIsFetching] = useState(false)
72152
- // const dispatch = useDispatch()
72153
- // const handleStartConversation = () => {
72154
- // if (
72155
- // !Object.keys({}).length &&
72156
- // !userSidebarLeft &&
72157
- // window.innerWidth < 992
72158
- // ) {
72159
- // handleSidebar()
72160
- // }
72161
- // }
72162
- // const uploadGroup = async (files: File[], type: 'image' | 'file') => {
72163
- // if (files.length === 0) { return }
72164
- // const batchId = newGuid()
72165
- // const errors: Array<{ file: File; error: any }> = []
72166
- // // Upload gửi từng file một
72167
- // for (const file of files) {
72168
- // try {
72169
- // const result = await uploadWithRetry(file)
72170
- // if (result.success && chatRoomId) {
72171
- // const infoFiles = result.data?.infoFiles || []
72172
- // const items = type === 'image' ? infoFiles.map((x: any) => ({ ...x, batchId, createdDate: new Date().toISOString() })) : infoFiles
72173
- // // Gửi message ngay sau khi upload thành công
72174
- // connectHub(chatRoomId, {
72175
- // sendTo: dataInfo.id,
72176
- // content: '',
72177
- // type,
72178
- // path: JSON.stringify(items),
72179
- // typeChat
72180
- // })
72181
- // } else {
72182
- // errors.push({ file, error: result.error })
72183
- // }
72184
- // } catch (error) {
72185
- // errors.push({ file, error })
72186
- // }
72187
- // }
72188
- // // Thông báo lỗi nếu có
72189
- // if (errors.length > 0) {
72190
- // notificationError(`${errors.length}/${files.length} ${type === 'image' ? 'ảnh' : 'file'} upload thất bại`)
72191
- // }
72192
- // }
72193
- // const dataURLToFile = (dataUrl: string, fileName: string) => {
72194
- // const [header, data] = dataUrl.split(',')
72195
- // const mime = header.match(/data:(.*?);/)?.[1] || 'image/png'
72196
- // const binary = atob(data)
72197
- // const len = binary.length
72198
- // const u8 = new Uint8Array(len)
72199
- // for (let i = 0; i < len; i++) { u8[i] = binary.charCodeAt(i) }
72200
- // return new File([u8], fileName, { type: mime })
72201
- // }
72202
- // // ** Extract tagUserIds from editor mentions
72203
- // const extractTagUserIds = (): string[] => {
72204
- // const tagUserIds: string[] = []
72205
- // let hasAllMention = false
72206
- // editor.getEditorState().read(() => {
72207
- // const root = $getRoot()
72208
- // const nodes = root.getAllTextNodes()
72209
- // nodes.forEach((node) => {
72210
- // if ($isMentionNode(node)) {
72211
- // const userId = (node as any).__userId
72212
- // if (userId === 'all') {
72213
- // hasAllMention = true
72214
- // } else if (userId && !tagUserIds.includes(userId)) {
72215
- // tagUserIds.push(userId)
72216
- // }
72217
- // }
72218
- // })
72219
- // })
72220
- // // Nếu có @All, lấy tất cả userId trong nhóm
72221
- // if (hasAllMention && groupChatUsers?.users) {
72222
- // const allUserIds = groupChatUsers.users
72223
- // .map((user: any) => user.id)
72224
- // .filter((id: string) => id !== dataProfile?.id) // Loại bỏ chính mình
72225
- // return allUserIds
72226
- // }
72227
- // return tagUserIds
72228
- // }
72229
- // // ** Sends New Msg
72230
- // const handleSendMsg = (message: any) => {
72231
- // if (imgCopy.length > 0) {
72232
- // const imageFiles: File[] = []
72233
- // const otherFiles: File[] = []
72234
- // imgCopy.forEach((item: any, idx: number) => {
72235
- // const data = item?.data || item
72236
- // if (typeof data === 'string' && data.startsWith('data:image')) {
72237
- // imageFiles.push(dataURLToFile(data, item.name || `pasted_${Date.now()}_${idx}.png`))
72238
- // } else if (data instanceof File) {
72239
- // if (data.type?.startsWith('image')) {
72240
- // imageFiles.push(data)
72241
- // } else {
72242
- // otherFiles.push(data)
72243
- // }
72244
- // }
72245
- // })
72246
- // // Gửi ảnh trước rồi file
72247
- // uploadGroup(imageFiles, 'image')
72248
- // uploadGroup(otherFiles, 'file')
72249
- // }
72250
- // if (message.trim().length) {
72251
- // if (typingTimeoutRef.current) {
72252
- // clearTimeout(typingTimeoutRef.current)
72253
- // }
72254
- // isTypingRef.current = false
72255
- // if (connection && chatRoomId) {
72256
- // connection.invoke('StopTyping', chatRoomId).catch(console.error)
72257
- // }
72258
- // const tagUserIds = extractTagUserIds()
72259
- // const id = typeChat === 'CHAT' ? chatRoomId : contactId
72260
- // if (id) {
72261
- // connectHub(id, {
72262
- // sendTo: dataInfo.id,
72263
- // content: message.trim(),
72264
- // replyContent: replyMessage?.currentMessage ? JSON.stringify(replyMessage.currentMessage) : null,
72265
- // path: null,
72266
- // type: 'text',
72267
- // typeChat,
72268
- // tagUserIds
72269
- // })
72270
- // }
72271
- // }
72272
- // setImgCopy([])
72273
- // }
72274
- // const uploadWithRetry = async (file: File, maxRetries = 2) => {
72275
- // let lastError
72276
- // for (let attempt = 0; attempt <= maxRetries; attempt++) {
72277
- // try {
72278
- // const formDataFile = new FormData()
72279
- // formDataFile.append('files', file, file.name)
72280
- // const rs = await uploadMultiFileApi(formDataFile).unwrap()
72281
- // return { success: true, data: rs }
72282
- // } catch (error: any) {
72283
- // lastError = error
72284
- // // Không retry nếu là lỗi validation từ server
72285
- // if (error?.status === 400 || error?.status === 413) {
72286
- // break
72287
- // }
72288
- // if (attempt < maxRetries) {
72289
- // // Exponential backoff: 1s, 2s, 4s...
72290
- // await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt))
72291
- // )
72292
- // }
72293
- // }
72294
- // }
72295
- // return {
72296
- // success: false,
72297
- // error: lastError?.message || 'Upload thất bại'
72298
- // }
72299
- // }
72300
- // const sendFile = async (event: any) => {
72301
- // if (event.target.files && event.target.files[0]) {
72302
- // const filesToUpload: File[] = Array.from(event.target.files)
72303
- // const errors: Array<{ file: File, error: any }> = []
72304
- // for (const file of filesToUpload) {
72305
- // const result = await uploadWithRetry(file)
72306
- // if (result.success && chatRoomId) {
72307
- // connectHub(chatRoomId, {
72308
- // sendTo: dataInfo.id,
72309
- // content: '',
72310
- // type: 'file',
72311
- // path: JSON.stringify(result.data?.infoFiles),
72312
- // typeChat
72313
- // })
72314
- // } else {
72315
- // errors.push({ file, error: result.error })
72316
- // }
72317
- // }
72318
- // if (errors.length > 0) {
72319
- // notificationError(`${errors.length} file upload thất bại`)
72320
- // }
72321
- // event.target.value = ''
72322
- // }
72323
- // }
72324
- // const sendImage = async (event: any) => {
72325
- // if (event.target.files && event.target.files[0]) {
72326
- // const filesToUpload: File[] = Array.from(event.target.files)
72327
- // const errors: Array<{ file: File, error: any }> = []
72328
- // const batchId = newGuid()
72329
- // for (const file of filesToUpload) {
72330
- // const result = await uploadWithRetry(file)
72331
- // const item = result.data?.infoFiles?.map((x: any) => ({ ...x, batchId, createdDate: new Date().toISOString() })) || []
72332
- // if (result.success && chatRoomId && result?.data?.status) {
72333
- // connectHub(chatRoomId, {
72334
- // sendTo: dataInfo.id,
72335
- // content: '',
72336
- // type: 'image',
72337
- // path: JSON.stringify(item),
72338
- // typeChat
72339
- // })
72340
- // } else {
72341
- // errors.push({ file, error: result.error })
72342
- // }
72343
- // }
72344
- // if (errors.length > 0) {
72345
- // notificationError(`${errors.length} ảnh upload thất bại`)
72346
- // }
72347
- // event.target.value = ''
72348
- // }
72349
- // }
72350
- // const handleRemoveImage = useCallback((idx: number) => {
72351
- // const newArr = [...imgCopy]
72352
- // newArr.splice(idx, 1)
72353
- // setImgCopy(newArr)
72354
- // }, [imgCopy])
72355
- // const onContextMenu = useCallback((e: any, chatMessage: any) => {
72356
- // const selection: any = window.document.getSelection()
72357
- // setIsOpen(true)
72358
- // setPosition({ x: e.clientX, y: e.clientY })
72359
- // if (e.target) {
72360
- // setCurrentMessage(chatMessage)
72361
- // }
72362
- // // Detect ảnh được click từ data attribute
72363
- // const fileIndex = e.target?.dataset?.fileIndex
72364
- // if (fileIndex !== undefined && chatMessage?.path) {
72365
- // setClickedImageFile(chatMessage.path[parseInt(fileIndex)])
72366
- // } else {
72367
- // setClickedImageFile(null)
72368
- // }
72369
- // e.preventDefault()
72370
- // const contextType = selection.toString() ? 'selection' : chatMessage?.type ? chatMessage.type : 'default'
72371
- // const config = CONTEXT_CONFIG[contextType]
72372
- // setListContextShow({ list: config.show, type: "SHOW" })
72373
- // setListContextHide({ list: config.hide, type: "HIDE" })
72374
- // }, [])
72375
- // const clearReply = () => {
72376
- // setReplyMessage(null)
72377
- // }
72378
- // const handleTypingStart = () => {
72379
- // if (!isTypingRef.current && connection && chatRoomId) {
72380
- // connection.invoke('StartTyping', chatRoomId).catch(console.error)
72381
- // isTypingRef.current = true
72382
- // }
72383
- // }
72384
- // const handleTypingStop = () => {
72385
- // if (typingTimeoutRef.current) { clearTimeout(typingTimeoutRef.current) }
72386
- // typingTimeoutRef.current = setTimeout(() => {
72387
- // if (isTypingRef.current && connection && chatRoomId) {
72388
- // connection.invoke('StopTyping', chatRoomId).catch(console.error)
72389
- // isTypingRef.current = false
72390
- // }
72391
- // }, 2000)
72392
- // }
72393
- // const handleChange = useCallback(
72394
- // (editorState: EditorState) => {
72395
- // if (
72396
- // inputContainer &&
72397
- // inputContainer.current &&
72398
- // inputContainer.current.clientHeight > 50
72399
- // ) {
72400
- // setIsMultiLine(true)
72401
- // } else {
72402
- // setIsMultiLine(false)
72403
- // }
72404
- // editorState.read(() => {
72405
- // handleTypingStart()
72406
- // handleTypingStop()
72407
- // })
72408
- // },
72409
- // [inputContainer, connection, chatRoomId]
72410
- // )
72411
- // const onEnter = (val: any) => {
72412
- // handleSendMsg(val)
72413
- // clearReply()
72414
- // setReplyMessage(null)
72415
- // }
72416
- // useEffect(() => {
72417
- // if (active) {
72418
- // setReplyMessage(null)
72419
- // setImgCopy([])
72420
- // setIsAtBottom(true)
72421
- // prevListLength.current = 0
72422
- // }
72423
- // }, [
72424
- // active,
72425
- // dataInfo
72426
- // //chatRoomId,
72427
- // //chatGetType
72428
- // ])
72429
- // // Chuyển phòng thì load lại message + pinned messages
72430
- // useEffect(() => {
72431
- // if (!chatRoomId && handleSidebar) { return }
72432
- // chatGetType(chatRoomId, undefined, "", "", undefined, undefined, 0, 0)
72433
- // if (chatRoomId) {
72434
- // getPinMessageChatRoomApi(chatRoomId)
72435
- // }
72436
- // }, [chatRoomId])
72437
- // const handleUnpinMessage = useCallback(async (message: any) => {
72438
- // const pinId = message?.pinId || message?.id
72439
- // if (!pinId) { return }
72440
- // await deletePinMessage(pinId)
72441
- // }, [deletePinMessage, chatRoomId])
72442
- // const handleViewPinnedMessage = useCallback((message: any) => {
72443
- // if (message?.id) {
72444
- // //setViewingPinnedMessage(message.id)
72445
- // // Tìm message element
72446
- // const element = document.getElementById(`msg-${message.id}`)
72447
- // const chatContainer = document.getElementById('scrollableDivChat')
72448
- // if (element && chatContainer) {
72449
- // // Lấy vị trí của element và container
72450
- // const elementRect = element.getBoundingClientRect()
72451
- // const containerRect = chatContainer.getBoundingClientRect()
72452
- // // Tính toán scroll position để đưa element vào giữa container
72453
- // const scrollTop = chatContainer.scrollTop
72454
- // const offset = elementRect.top - containerRect.top - (containerRect.height / 2) + (elementRect.height / 2)
72455
- // // Scroll trong container, không scroll toàn page
72456
- // chatContainer.scrollTo({
72457
- // top: scrollTop + offset,
72458
- // behavior: 'smooth'
72459
- // })
72460
- // // Highlight message
72461
- // const originalBg = element.style.backgroundColor
72462
- // const originalZIndex = element.style.zIndex
72463
- // element.style.backgroundColor = '#fff3cd'
72464
- // element.style.zIndex = '1000'
72465
- // element.style.position = 'relative'
72466
- // element.style.transition = 'background-color 0.3s'
72467
- // // Auto close sau 500ms
72468
- // setTimeout(() => {
72469
- // element.style.backgroundColor = originalBg || ''
72470
- // element.style.zIndex = originalZIndex || ''
72471
- // //setViewingPinnedMessage(null)
72472
- // }, 500)
72473
- // } else {
72474
- // console.log('Message not found in current view, may need to load more messages')
72475
- // setTimeout(() => {
72476
- // //setViewingPinnedMessage(null)
72477
- // }, 2000)
72478
- // }
72479
- // }
72480
- // }, [])
72176
+ useCallback((mes) => {
72177
+ setSelectedMessage(mes);
72178
+ setOpenModalPreview(true);
72179
+ }, []);
72180
+ useState(false);
72181
+ useDispatch();
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
+ }, []);
72481
72309
  // const onKeyDown = (event: any) => {
72482
72310
  // if (event.code === 'NumpadEnter') {
72483
72311
  // event.preventDefault()