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

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
@@ -72110,7 +72110,7 @@ const ChatLog = (props) => {
72110
72110
  const prevListLength = useRef(0);
72111
72111
  useState(0);
72112
72112
  useState(true);
72113
- useState(new Set());
72113
+ const [expandedMessages, setExpandedMessages] = useState(new Set());
72114
72114
  const [clickedImageFile, setClickedImageFile] = useState(null);
72115
72115
  useState(false);
72116
72116
  useState(new Set());
@@ -72155,7 +72155,7 @@ const ChatLog = (props) => {
72155
72155
  scrollToBottom();
72156
72156
  }
72157
72157
  }, [messageByGroup, checkScroll]);
72158
- useMemo(() => {
72158
+ const mentionItems = useMemo(() => {
72159
72159
  if (!groupChatUsers) {
72160
72160
  return [];
72161
72161
  }
@@ -72173,7 +72173,7 @@ const ChatLog = (props) => {
72173
72173
  });
72174
72174
  return [{ id: "all", name: "All" }, ...mappedUsers];
72175
72175
  }, [groupChatUsers]);
72176
- useCallback((mes) => {
72176
+ const handlePreview = useCallback((mes) => {
72177
72177
  setSelectedMessage(mes);
72178
72178
  setOpenModalPreview(true);
72179
72179
  }, []);
@@ -72306,322 +72306,174 @@ const ChatLog = (props) => {
72306
72306
  }
72307
72307
  }
72308
72308
  }, []);
72309
- // const onKeyDown = (event: any) => {
72310
- // if (event.code === 'NumpadEnter') {
72311
- // event.preventDefault()
72312
- // const baseOptions = {
72313
- // key: 'Enter',
72314
- // code: 'Enter',
72315
- // which: 13,
72316
- // keyCode: 13,
72317
- // bubbles: true,
72318
- // shiftKey: event.shiftKey,
72319
- // altKey: event.altKey,
72320
- // ctrlKey: event.ctrlKey,
72321
- // metaKey: event.metaKey
72322
- // }
72323
- // const newEvent = new KeyboardEvent('keydown', baseOptions)
72324
- // event.target.dispatchEvent(newEvent)
72325
- // }
72326
- // }
72327
- // const useParsedChatData = (chatMsg: string) => {
72328
- // if (!chatMsg) { return {} }
72329
- // try {
72330
- // return typeof chatMsg === 'string' ? JSON.parse(chatMsg) : chatMsg
72331
- // } catch (err) {
72332
- // console.error('JSON parse error:', err)
72333
- // return {}
72334
- // }
72335
- // }
72336
- // const renderChatText = useCallback((chat: any) => {
72337
- // const isPath = Array.isArray(chat?.path) && typeof chat.path[0]?.path === "string" ? chat.path[0].path.trim() : ""
72338
- // const img = isPath ? `${CDN_URL_VIEW}/${isPath}` : ""
72339
- // const toggleExpanded = (messageId: string) => {
72340
- // const newExpanded = new Set(expandedMessages)
72341
- // if (newExpanded.has(messageId)) {
72342
- // newExpanded.delete(messageId)
72343
- // } else {
72344
- // newExpanded.add(messageId)
72345
- // }
72346
- // setExpandedMessages(newExpanded)
72347
- // }
72348
- // const formatMentionsReact = (text: string, mentions: any[], messageId: string) => {
72349
- // if (!text || !mentions || mentions.length === 0) { return text }
72350
- // const maxLength = 200
72351
- // const isExpanded = expandedMessages.has(messageId)
72352
- // let displayText = text
72353
- // let isTruncated = false
72354
- // if (!isExpanded && text.length > maxLength) {
72355
- // displayText = text.substring(0, maxLength)
72356
- // isTruncated = true
72357
- // }
72358
- // // Chỉ highlight những mention có trong danh sách
72359
- // let result: any = displayText
72360
- // // Hàm helper để xử lý mention trong cả string và array
72361
- // const processMention = (text: string, mention: any): any => {
72362
- // const escapedName = mention?.name?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
72363
- // const mentionRegex = new RegExp(`@${escapedName}(?=\\s|$|[.,;:!?()[\\]{}'"\`~@])`, 'g')
72364
- // const parts = text.split(mentionRegex)
72365
- // const matches = text.match(mentionRegex) || []
72366
- // if (matches.length === 0) {
72367
- // return text
72368
- // }
72369
- // const newParts: any[] = []
72370
- // parts.forEach((part: any, index: any) => {
72371
- // newParts.push(part)
72372
- // if (matches[index]) {
72373
- // newParts.push(
72374
- // <span key={`mention-${messageId}-${mention.id || mention.name}-${index}`} className="chat-mention">
72375
- // {matches[index]}
72376
- // </span>
72377
- // )
72378
- // }
72379
- // })
72380
- // return newParts
72381
- // }
72382
- // mentions.forEach((mention: any) => {
72383
- // if (typeof result === 'string') {
72384
- // result = processMention(result, mention)
72385
- // } else if (Array.isArray(result)) {
72386
- // // Xử từng phần tử trong array
72387
- // const processedArray: any[] = []
72388
- // result.forEach((item: any) => {
72389
- // if (typeof item === 'string') {
72390
- // const processed = processMention(item, mention)
72391
- // if (Array.isArray(processed)) {
72392
- // processedArray.push(...processed)
72393
- // } else {
72394
- // processedArray.push(processed)
72395
- // }
72396
- // } else {
72397
- // // Giữ nguyên các React elements đã được xử
72398
- // processedArray.push(item)
72399
- // }
72400
- // })
72401
- // result = processedArray
72402
- // }
72403
- // })
72404
- // // Add expand/collapse functionality
72405
- // if (isTruncated || (isExpanded && text.length > maxLength)) {
72406
- // const expandButton = (
72407
- // <span
72408
- // key={`expand-${messageId}`}
72409
- // onClick={() => toggleExpanded(messageId)}
72410
- // style={{
72411
- // color: '#006edc',
72412
- // cursor: 'pointer',
72413
- // fontWeight: 500,
72414
- // marginLeft: 5
72415
- // }}
72416
- // >
72417
- // {isExpanded ? ' Thu gọn' : '... Mở rộng'}
72418
- // </span>
72419
- // )
72420
- // if (Array.isArray(result)) {
72421
- // result.push(expandButton)
72422
- // } else {
72423
- // result = [result, expandButton]
72424
- // }
72425
- // }
72426
- // return result
72427
- // }
72428
- // return (
72429
- // <>
72430
- // <div>
72431
- // <div>
72432
- // {chat.path && chat.path.length === 1 && (
72433
- // <div className="image-container">
72434
- // {img && <img src={img} alt="" />}
72435
- // </div>
72436
- // )}
72437
- // {isValidUrl(chat.msg) && renderLinkPreview(chat.msg)}
72438
- // {chat.msg && !isValidUrl(chat.msg) ? (
72439
- // <div>{formatMentionsReact(chat.msg, mentionItems, chat.id)}</div>
72440
- // ) : (
72441
- // <></>
72442
- // )}
72443
- // {chat.path && chat.path.length > 1 && (
72444
- // <div className="group-image">
72445
- // {chat.path.map((it: any, index: any) => {
72446
- // return (
72447
- // <div
72448
- // key={index}
72449
- // className="group-image-item image-container"
72450
- // >
72451
- // <img
72452
- // style={{ maxWidth: "100%", maxHeight: 360 }}
72453
- // src={`${CDN_URL_VIEW}/${it.path.trim()}`}
72454
- // onClick={() => handlePreview(it)}
72455
- // alt=""
72456
- // />
72457
- // </div>
72458
- // )
72459
- // })}
72460
- // </div>
72461
- // )}
72462
- // <div className="" style={{ fontSize: "12px", color: "#476285" }}>
72463
- // {moment(chat.time).format("HH:mm")}
72464
- // </div>
72465
- // </div>
72466
- // </div>
72467
- // </>
72468
- // )
72469
- // }, [expandedMessages, handlePreview, mentionItems])
72470
- // const getLinkPreviewData = (urlString: string) => {
72471
- // try {
72472
- // const hasProtocol = /^https?:\/\//i.test(urlString)
72473
- // const href = hasProtocol ? urlString : `https://${urlString}`
72474
- // const url = new URL(href)
72475
- // const displayUrl =
72476
- // urlString.length > 80 ? `${urlString.slice(0, 77)}...` : urlString
72477
- // return {
72478
- // href,
72479
- // displayUrl,
72480
- // host: url.host
72481
- // }
72482
- // } catch (e) {
72483
- // return {
72484
- // href: urlString,
72485
- // displayUrl: urlString,
72486
- // host: ''
72487
- // }
72488
- // }
72489
- // }
72490
- // const renderLinkPreview = (urlString: string) => {
72491
- // const { href, displayUrl, host } = getLinkPreviewData(urlString)
72492
- // return (
72493
- // <>
72494
- // <a
72495
- // href={href}
72496
- // target="_blank"
72497
- // rel="noreferrer"
72498
- // style={{
72499
- // textDecoration: 'none',
72500
- // color: 'inherit'
72501
- // }}
72502
- // >
72503
- // <div
72504
- // style={{
72505
- // marginTop: 4,
72506
- // marginBottom: 4,
72507
- // padding: '8px 10px',
72508
- // borderRadius: 8,
72509
- // backgroundColor: '#eef5ff',
72510
- // border: '1px solid #d3e2ff',
72511
- // maxWidth: 420
72512
- // }}
72513
- // >
72514
- // <div
72515
- // style={{
72516
- // fontSize: 14,
72517
- // fontWeight: 500,
72518
- // color: '#1d4f91',
72519
- // wordBreak: 'break-word'
72520
- // }}
72521
- // >
72522
- // {displayUrl}
72523
- // </div>
72524
- // {host && (
72525
- // <div
72526
- // style={{
72527
- // marginTop: 4,
72528
- // fontSize: 12,
72529
- // color: '#6f6b7d'
72530
- // }}
72531
- // >
72532
- // {host}
72533
- // </div>
72534
- // )}
72535
- // </div>
72536
- // </a>
72537
- // </>
72538
- // )
72539
- // }
72540
- // const renderNotifyLeaveGroup = useCallback((chat: any) => {
72541
- // const msg = JSON.parse(chat?.msg)
72542
- // if (chat?.createdById === dataProfile?.id) {
72543
- // return (
72544
- // <>
72545
- // <div>
72546
- // <span style={{ fontWeight: "bold", marginRight: "5px" }}>
72547
- // {msg?.name}
72548
- // </span>
72549
- // <span>được bạn xoá khỏi nhóm</span>
72550
- // </div>
72551
- // </>
72552
- // )
72553
- // }
72554
- // if (chat?.createdById === msg?.id) {
72555
- // return (
72556
- // <>
72557
- // <div>
72558
- // <span style={{ fontWeight: "bold", marginRight: "5px" }}>
72559
- // {msg?.name}
72560
- // </span>
72561
- // <span>đã rời khỏi nhóm</span>
72562
- // </div>
72563
- // </>
72564
- // )
72565
- // }
72566
- // return (
72567
- // <>
72568
- // <div>
72569
- // <span style={{ fontWeight: "bold", marginRight: "5px" }}>
72570
- // {msg?.name}
72571
- // </span>
72572
- // <span>được <span style={{ fontWeight: "bold", marginRight: "5px" }}>{chat?.createdBy?.name}</span> xoá khỏi nhóm</span>
72573
- // </div>
72574
- // </>
72575
- // )
72576
- // }, [dataProfile])
72577
- // const renderChatNotification = useCallback((chat: any) => {
72578
- // const parseChatMsg = (msg: string) => {
72579
- // if (!msg) { return [] }
72580
- // try {
72581
- // const parsed = typeof msg === 'string' ? JSON.parse(msg) : msg
72582
- // return Array.isArray(parsed) ? parsed : [parsed]
72583
- // } catch (err) {
72584
- // console.error('JSON parse error:', err)
72585
- // return []
72586
- // }
72587
- // }
72588
- // const dataParse = parseChatMsg(chat.msg)
72589
- // // ✅ FIX: Kiểm tra array trước khi dùng slice
72590
- // if (!Array.isArray(dataParse) || dataParse.length === 0) {
72591
- // return (
72592
- // <div>
72593
- // <span>Đã có thay đổi trong nhóm</span>
72594
- // </div>
72595
- // )
72596
- // }
72597
- // const displayedItems = dataParse.slice(0, 2)
72598
- // const extraCount = Math.max(0, dataParse.length - displayedItems.length)
72599
- // return (
72600
- // <>
72601
- // <div>
72602
- // {displayedItems.map((item: any, index: any) => (
72603
- // <strong key={index}>
72604
- // {item.name}
72605
- // {index < displayedItems.length - 1 && ", "}
72606
- // </strong>
72607
- // ))}
72608
- // {dataParse.length > 3 && (
72609
- // <strong>
72610
- // <span style={{ fontWeight: "normal" }}>{" và "}</span>{" "}
72611
- // {extraCount} người khác
72612
- // </strong>
72613
- // )}
72614
- // {" được "}
72615
- // {chat?.createdBy?.id === dataProfile?.id ? (
72616
- // <span>bạn </span>
72617
- // ) : (
72618
- // <strong style={{ marginRight: "5px" }}>{chat?.createdByName}</strong>
72619
- // )}
72620
- // thêm vào nhóm
72621
- // </div>
72622
- // </>
72623
- // )
72624
- // }, [dataProfile])
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ử 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ử 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]);
72400
+ const getLinkPreviewData = (urlString) => {
72401
+ try {
72402
+ const hasProtocol = /^https?:\/\//i.test(urlString);
72403
+ const href = hasProtocol ? urlString : `https://${urlString}`;
72404
+ const url = new URL(href);
72405
+ const displayUrl = urlString.length > 80 ? `${urlString.slice(0, 77)}...` : urlString;
72406
+ return {
72407
+ href,
72408
+ displayUrl,
72409
+ host: url.host
72410
+ };
72411
+ }
72412
+ catch (e) {
72413
+ return {
72414
+ href: urlString,
72415
+ displayUrl: urlString,
72416
+ host: ''
72417
+ };
72418
+ }
72419
+ };
72420
+ const renderLinkPreview = (urlString) => {
72421
+ const { href, displayUrl, host } = getLinkPreviewData(urlString);
72422
+ return (jsx(Fragment$1, { children: jsx("a", { href: href, target: "_blank", rel: "noreferrer", style: {
72423
+ textDecoration: 'none',
72424
+ color: 'inherit'
72425
+ }, children: jsxs("div", { style: {
72426
+ marginTop: 4,
72427
+ marginBottom: 4,
72428
+ padding: '8px 10px',
72429
+ borderRadius: 8,
72430
+ backgroundColor: '#eef5ff',
72431
+ border: '1px solid #d3e2ff',
72432
+ maxWidth: 420
72433
+ }, children: [jsx("div", { style: {
72434
+ fontSize: 14,
72435
+ fontWeight: 500,
72436
+ color: '#1d4f91',
72437
+ wordBreak: 'break-word'
72438
+ }, children: displayUrl }), host && (jsx("div", { style: {
72439
+ marginTop: 4,
72440
+ fontSize: 12,
72441
+ color: '#6f6b7d'
72442
+ }, children: host }))] }) }) }));
72443
+ };
72444
+ useCallback((chat) => {
72445
+ const msg = JSON.parse(chat?.msg);
72446
+ if (chat?.createdById === dataProfile?.id) {
72447
+ return (jsx(Fragment$1, { children: jsxs("div", { children: [jsx("span", { style: { fontWeight: "bold", marginRight: "5px" }, children: msg?.name }), jsx("span", { children: "\u0111\u01B0\u1EE3c b\u1EA1n xo\u00E1 kh\u1ECFi nh\u00F3m" })] }) }));
72448
+ }
72449
+ if (chat?.createdById === msg?.id) {
72450
+ return (jsx(Fragment$1, { children: jsxs("div", { children: [jsx("span", { style: { fontWeight: "bold", marginRight: "5px" }, children: msg?.name }), jsx("span", { children: "\u0111\u00E3 r\u1EDDi kh\u1ECFi nh\u00F3m" })] }) }));
72451
+ }
72452
+ return (jsx(Fragment$1, { children: jsxs("div", { children: [jsx("span", { style: { fontWeight: "bold", marginRight: "5px" }, children: msg?.name }), jsxs("span", { children: ["\u0111\u01B0\u1EE3c ", jsx("span", { style: { fontWeight: "bold", marginRight: "5px" }, children: chat?.createdBy?.name }), " xo\u00E1 kh\u1ECFi nh\u00F3m"] })] }) }));
72453
+ }, [dataProfile]);
72454
+ useCallback((chat) => {
72455
+ const parseChatMsg = (msg) => {
72456
+ if (!msg) {
72457
+ return [];
72458
+ }
72459
+ try {
72460
+ const parsed = typeof msg === 'string' ? JSON.parse(msg) : msg;
72461
+ return Array.isArray(parsed) ? parsed : [parsed];
72462
+ }
72463
+ catch (err) {
72464
+ console.error('JSON parse error:', err);
72465
+ return [];
72466
+ }
72467
+ };
72468
+ const dataParse = parseChatMsg(chat.msg);
72469
+ // FIX: Kiểm tra array trước khi dùng slice
72470
+ if (!Array.isArray(dataParse) || dataParse.length === 0) {
72471
+ return (jsx("div", { children: jsx("span", { children: "\u0110\u00E3 c\u00F3 thay \u0111\u1ED5i trong nh\u00F3m" }) }));
72472
+ }
72473
+ const displayedItems = dataParse.slice(0, 2);
72474
+ const extraCount = Math.max(0, dataParse.length - displayedItems.length);
72475
+ return (jsx(Fragment$1, { children: jsxs("div", { children: [displayedItems.map((item, index) => (jsxs("strong", { children: [item.name, index < displayedItems.length - 1 && ", "] }, index))), dataParse.length > 3 && (jsxs("strong", { children: [jsx("span", { style: { fontWeight: "normal" }, children: " và " }), " ", extraCount, " ng\u01B0\u1EDDi kh\u00E1c"] })), " được ", chat?.createdBy?.id === dataProfile?.id ? (jsx("span", { children: "b\u1EA1n " })) : (jsx("strong", { style: { marginRight: "5px" }, children: chat?.createdByName })), "th\u00EAm v\u00E0o nh\u00F3m"] }) }));
72476
+ }, [dataProfile]);
72625
72477
  // const renderChatImage = useCallback((chat: any) => {
72626
72478
  // const files = chat.path
72627
72479
  // if (!files || !Array.isArray(files) || files.length === 0) {