@ermis-network/ermis-chat-react 1.0.9 → 2.0.1
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/README.md +144 -0
- package/dist/index.cjs +8320 -3427
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1277 -291
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +1131 -99
- package/dist/index.d.ts +1131 -99
- package/dist/index.mjs +8168 -3319
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -4
- package/src/channelTypeUtils.ts +1 -1
- package/src/components/Avatar.tsx +2 -1
- package/src/components/Channel.tsx +6 -5
- package/src/components/ChannelActions.tsx +67 -3
- package/src/components/ChannelHeader.tsx +27 -37
- package/src/components/ChannelInfo/AddMemberModal.tsx +12 -2
- package/src/components/ChannelInfo/ChannelInfo.tsx +410 -187
- package/src/components/ChannelInfo/ChannelInfoTabs.tsx +59 -297
- package/src/components/ChannelInfo/ChannelSettingsPanel.tsx +30 -174
- package/src/components/ChannelInfo/EditChannelModal.tsx +6 -3
- package/src/components/ChannelInfo/MediaGridItem.tsx +215 -68
- package/src/components/ChannelInfo/MemberListItem.tsx +2 -3
- package/src/components/ChannelInfo/MessageSearchPanel.tsx +27 -126
- package/src/components/ChannelInfo/States.tsx +1 -1
- package/src/components/ChannelInfo/index.ts +3 -0
- package/src/components/ChannelInfo/useChannelInfoTabs.tsx +427 -0
- package/src/components/ChannelInfo/useChannelSettings.ts +212 -0
- package/src/components/ChannelInfo/useMessageSearch.tsx +141 -0
- package/src/components/ChannelList.tsx +247 -301
- package/src/components/CreateChannelModal.tsx +290 -93
- package/src/components/Dropdown.tsx +1 -16
- package/src/components/EditPreview.tsx +1 -0
- package/src/components/ErmisCallProvider.tsx +72 -17
- package/src/components/ErmisCallUI.tsx +43 -20
- package/src/components/FilesPreview.tsx +8 -12
- package/src/components/FlatTopicGroupItem.tsx +243 -0
- package/src/components/ForwardMessageModal.tsx +43 -81
- package/src/components/MediaLightbox.tsx +454 -292
- package/src/components/MentionSuggestions.tsx +47 -35
- package/src/components/MessageActionsBox.tsx +6 -1
- package/src/components/MessageInput.tsx +165 -17
- package/src/components/MessageInputDefaults.tsx +127 -1
- package/src/components/MessageItem.tsx +155 -43
- package/src/components/MessageQuickReactions.tsx +153 -23
- package/src/components/MessageReactions.tsx +49 -3
- package/src/components/MessageRenderers.tsx +1114 -445
- package/src/components/Panel.tsx +1 -14
- package/src/components/PinnedMessages.tsx +55 -15
- package/src/components/PreviewOverlay.tsx +24 -0
- package/src/components/QuotedMessagePreview.tsx +99 -8
- package/src/components/ReadReceipts.tsx +2 -1
- package/src/components/RecoveryPin/RecoveryPin.tsx +279 -0
- package/src/components/RecoveryPin/index.ts +19 -0
- package/src/components/TopicList.tsx +236 -0
- package/src/components/TopicModal.tsx +4 -1
- package/src/components/TypingIndicator.tsx +17 -8
- package/src/components/UserPicker.tsx +94 -16
- package/src/components/VirtualMessageList.tsx +419 -113
- package/src/context/ChatComponentsContext.tsx +14 -0
- package/src/context/ChatProvider.tsx +44 -14
- package/src/context/ErmisCallContext.tsx +4 -0
- package/src/hooks/useChannelCapabilities.ts +7 -4
- package/src/hooks/useChannelData.ts +10 -3
- package/src/hooks/useChannelListUpdates.ts +94 -21
- package/src/hooks/useChannelMessages.ts +391 -42
- package/src/hooks/useChannelRowUpdates.ts +36 -5
- package/src/hooks/useChatUser.ts +39 -0
- package/src/hooks/useContactChannels.ts +45 -0
- package/src/hooks/useContactCount.ts +50 -0
- package/src/hooks/useDownloadHandler.ts +36 -0
- package/src/hooks/useDragAndDrop.ts +79 -0
- package/src/hooks/useE2eeAttachmentRenderer.ts +204 -0
- package/src/hooks/useE2eeFileUpload.ts +38 -0
- package/src/hooks/useFileUpload.ts +25 -5
- package/src/hooks/useForwardMessage.ts +309 -0
- package/src/hooks/useInviteChannels.ts +88 -0
- package/src/hooks/useInviteCount.ts +104 -0
- package/src/hooks/useLoadMessages.ts +16 -4
- package/src/hooks/useMentions.ts +60 -7
- package/src/hooks/useMessageActions.ts +19 -10
- package/src/hooks/useMessageSend.ts +64 -12
- package/src/hooks/usePendingE2eeSends.ts +29 -0
- package/src/hooks/usePendingState.ts +21 -4
- package/src/hooks/usePreviewState.ts +69 -0
- package/src/hooks/useRecoveryPin.ts +287 -0
- package/src/hooks/useScrollToMessage.ts +29 -4
- package/src/hooks/useStickerPicker.ts +62 -0
- package/src/hooks/useTopicGroupUpdates.ts +235 -0
- package/src/index.ts +79 -6
- package/src/messageTypeUtils.ts +27 -1
- package/src/styles/_base.css +0 -1
- package/src/styles/_call-ui.css +59 -2
- package/src/styles/_channel-info.css +50 -4
- package/src/styles/_channel-list.css +131 -68
- package/src/styles/_create-channel-modal.css +10 -0
- package/src/styles/_forward-modal.css +16 -1
- package/src/styles/_media-lightbox.css +67 -2
- package/src/styles/_mentions.css +1 -1
- package/src/styles/_message-actions.css +3 -4
- package/src/styles/_message-bubble.css +631 -112
- package/src/styles/_message-input.css +139 -0
- package/src/styles/_message-list.css +91 -18
- package/src/styles/_message-quick-reactions.css +105 -32
- package/src/styles/_message-reactions.css +22 -32
- package/src/styles/_modal.css +2 -1
- package/src/styles/_preview-overlay.css +38 -0
- package/src/styles/_recovery-pin.css +97 -0
- package/src/styles/_tokens.css +22 -20
- package/src/styles/_typing-indicator.css +26 -10
- package/src/styles/index.css +2 -0
- package/src/types.ts +477 -15
- package/src/utils/avatarColors.ts +48 -0
- package/src/utils.ts +219 -16
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context/ChatProvider.tsx","../src/components/ErmisCallProvider.tsx","../src/context/ErmisCallContext.tsx","../src/components/ErmisCallUI.tsx","../src/hooks/useCallContext.ts","../src/components/Modal.tsx","../src/components/Avatar.tsx","../src/components/MediaLightbox.tsx","../src/utils.ts","../src/hooks/useChatClient.ts","../src/hooks/useChannel.ts","../src/hooks/useChannelListUpdates.ts","../src/channelTypeUtils.ts","../src/channelRoleUtils.ts","../src/hooks/useChannelRowUpdates.ts","../src/hooks/useBannedState.ts","../src/hooks/useBlockedState.ts","../src/hooks/useOnlineStatus.ts","../src/hooks/useOnlineUsers.ts","../src/hooks/usePendingState.ts","../src/components/ChannelList.tsx","../src/components/TopicModal.tsx","../src/components/ChannelActions.tsx","../src/components/Dropdown.tsx","../src/components/Channel.tsx","../src/components/ForwardMessageModal.tsx","../src/components/ChannelHeader.tsx","../src/components/VirtualMessageList.tsx","../src/hooks/useLoadMessages.ts","../src/hooks/useScrollToMessage.ts","../src/hooks/useChannelMessages.ts","../src/hooks/useChannelData.ts","../src/components/MessageItem.tsx","../src/components/QuotedMessagePreview.tsx","../src/components/MessageActionsBox.tsx","../src/hooks/useMessageActions.ts","../src/hooks/useChannelCapabilities.ts","../src/messageTypeUtils.ts","../src/components/MessageReactions.tsx","../src/components/MessageQuickReactions.tsx","../src/components/MessageRenderers.tsx","../src/components/ChannelInfo/utils.tsx","../src/components/PinnedMessages.tsx","../src/components/ReadReceipts.tsx","../src/components/TypingIndicator.tsx","../src/hooks/useTypingIndicator.ts","../src/components/PendingOverlay.tsx","../src/components/SkippedOverlay.tsx","../src/components/BannedOverlay.tsx","../src/components/ClosedTopicOverlay.tsx","../src/components/MessageInput.tsx","../src/hooks/useMentions.ts","../src/hooks/useFileUpload.ts","../src/hooks/useEmojiPicker.ts","../src/hooks/useMessageSend.ts","../src/components/MessageInputDefaults.tsx","../src/components/MentionSuggestions.tsx","../src/components/FilesPreview.tsx","../src/components/ReplyPreview.tsx","../src/components/EditPreview.tsx","../src/components/ChannelInfo/ChannelInfo.tsx","../src/components/ChannelInfo/ChannelInfoTabs.tsx","../src/components/ChannelInfo/MediaGridItem.tsx","../src/components/ChannelInfo/LinkListItem.tsx","../src/components/ChannelInfo/FileListItem.tsx","../src/components/ChannelInfo/MemberListItem.tsx","../src/components/ChannelInfo/States.tsx","../src/components/ChannelInfo/AddMemberModal.tsx","../src/components/UserPicker.tsx","../src/components/ChannelInfo/EditChannelModal.tsx","../src/components/ChannelInfo/MessageSearchPanel.tsx","../src/components/Panel.tsx","../src/components/ChannelInfo/ChannelSettingsPanel.tsx","../src/components/CreateChannelModal.tsx"],"sourcesContent":["import React, { createContext, useState, useCallback } from 'react';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { Theme, ChatContextValue, ChatProviderProps, ReadStateEntry } from '../types';\nimport { ErmisCallProvider } from '../components/ErmisCallProvider';\nimport { ErmisCallUI } from '../components/ErmisCallUI';\n\nexport type { Theme, ChatContextValue, ChatProviderProps } from '../types';\n\nexport const ChatContext = createContext<ChatContextValue | null>(null);\n\nexport const ChatProvider: React.FC<ChatProviderProps> = ({\n client,\n children,\n initialTheme = 'light',\n enableCall = false,\n callSessionId,\n callWasmPath,\n callRelayUrl,\n CallUIComponent,\n incomingCallAudioPath,\n outgoingCallAudioPath,\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [activeChannelRaw, setActiveChannelRaw] = useState<Channel | null>(null);\n const [theme, setTheme] = useState<Theme>(initialTheme);\n const [messages, setMessages] = useState<FormatMessageResponse[]>([]);\n const [quotedMessage, setQuotedMessage] = useState<FormatMessageResponse | null>(null);\n const [editingMessage, setEditingMessage] = useState<FormatMessageResponse | null>(null);\n const [readState, setReadState] = useState<Record<string, ReadStateEntry>>({});\n const [forwardingMessage, setForwardingMessage] = useState<FormatMessageResponse | null>(null);\n const [jumpToMessageId, setJumpToMessageId] = useState<string | null>(null);\n\n const activeChannel = activeChannelRaw;\n\n const setActiveChannel = useCallback((channel: Channel | null) => {\n setActiveChannelRaw(channel);\n setQuotedMessage(null);\n setEditingMessage(null);\n if (channel) {\n setMessages([...channel.state.latestMessages]);\n setReadState({ ...channel.state.read });\n } else {\n setMessages([]);\n setReadState({});\n }\n }, []);\n\n /** Re-read messages from SDK state into React state */\n const syncMessages = useCallback(() => {\n if (activeChannel) {\n setMessages([...activeChannel.state.latestMessages]);\n }\n }, [activeChannel]);\n\n const value: ChatContextValue = {\n client,\n activeChannel,\n setActiveChannel,\n theme,\n setTheme,\n messages,\n setMessages,\n syncMessages,\n quotedMessage,\n setQuotedMessage,\n editingMessage,\n setEditingMessage,\n readState,\n setReadState,\n forwardingMessage,\n setForwardingMessage,\n jumpToMessageId,\n setJumpToMessageId,\n enableCall,\n };\n\n const CallUIView = CallUIComponent ? <CallUIComponent /> : (\n <ErmisCallUI\n incomingCallAudioPath={incomingCallAudioPath}\n outgoingCallAudioPath={outgoingCallAudioPath}\n />\n );\n\n const content = (\n <ChatContext.Provider value={value}>\n <div className={`ermis-chat ermis-chat--${theme}`}>\n {children}\n {enableCall && CallUIView}\n </div>\n </ChatContext.Provider>\n );\n\n if (enableCall) {\n if (!callSessionId) {\n console.warn('ErmisChat React: enableCall is true but callSessionId is missing.');\n }\n return (\n <ErmisCallProvider\n client={client}\n sessionId={callSessionId || ''}\n wasmPath={callWasmPath}\n relayUrl={callRelayUrl}\n onCallStart={onCallStart}\n onCallEnd={onCallEnd}\n onCallError={onCallError}\n onIncomingCall={onIncomingCall}\n onCallAccepted={onCallAccepted}\n onCallRejected={onCallRejected}\n >\n {content}\n </ErmisCallProvider>\n );\n }\n\n return content;\n};\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { CallStatus, ErmisCallNode, type UserCallInfo, type CallEventData } from '@ermis-network/ermis-chat-sdk';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport type { ErmisCallProviderProps } from '../types';\n\nexport type { ErmisCallProviderProps } from '../types';\n\nexport const ErmisCallProvider: React.FC<ErmisCallProviderProps> = ({\n children,\n client,\n sessionId,\n wasmPath = '/ermis_call_node_wasm_bg.wasm',\n relayUrl = 'https://iroh-relay.ermis.network:8443',\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [callNode, setCallNode] = useState<ErmisCallNode | null>(null);\n const [callStatus, setCallStatus] = useState<CallStatus | ''>('');\n const [localStream, setLocalStream] = useState<MediaStream | null>(null);\n const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null);\n const [callType, setCallType] = useState<string>('audio');\n const [callerInfo, setCallerInfo] = useState<UserCallInfo | undefined>(undefined);\n const [receiverInfo, setReceiverInfo] = useState<UserCallInfo | undefined>(undefined);\n const [isIncoming, setIsIncoming] = useState<boolean>(false);\n const [isMicMuted, setIsMicMuted] = useState(false);\n const [isVideoMuted, setIsVideoMuted] = useState(true); // Default to true until a video track is added\n const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([]);\n const [videoDevices, setVideoDevices] = useState<MediaDeviceInfo[]>([]);\n const [selectedAudioDeviceId, setSelectedAudioDeviceId] = useState<string>('');\n const [selectedVideoDeviceId, setSelectedVideoDeviceId] = useState<string>('');\n const [isScreenSharing, setIsScreenSharing] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [isRemoteMicMuted, setIsRemoteMicMuted] = useState(false);\n const [isRemoteVideoMuted, setIsRemoteVideoMuted] = useState(false);\n\n // Call duration timer (C7 — exposed via context)\n const [callDuration, setCallDuration] = useState(0);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const startTimer = useCallback(() => {\n setCallDuration(0);\n timerRef.current = setInterval(() => {\n setCallDuration((prev) => prev + 1);\n }, 1000);\n }, []);\n\n const stopTimer = useCallback(() => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n setCallDuration(0);\n }, []);\n\n useEffect(() => {\n if (callStatus === CallStatus.CONNECTED) {\n startTimer();\n } else {\n stopTimer();\n }\n return () => stopTimer();\n }, [callStatus, startTimer, stopTimer]);\n\n useEffect(() => {\n if (!client || !sessionId) return;\n\n // Create new call node instance\n const node = new ErmisCallNode(client, sessionId, wasmPath, relayUrl);\n setCallNode(node);\n\n // Register Call Events\n node.onCallEvent = (data: CallEventData) => {\n setIsIncoming(data.type === 'incoming');\n setCallType(data.callType);\n setCallerInfo(data.callerInfo);\n setReceiverInfo(data.receiverInfo);\n // C1: Lifecycle callback — incoming call\n if (data.type === 'incoming' && data.callerInfo) {\n onIncomingCall?.(data.callerInfo);\n }\n };\n\n node.onError = (error: string) => {\n setErrorMessage(error);\n // C1: Lifecycle callback — error\n onCallError?.(error);\n };\n node.onDeviceChange = (audio, video) => {\n setAudioDevices(audio);\n setVideoDevices(video);\n };\n node.onScreenShareChange = (isSharing: boolean) => setIsScreenSharing(isSharing);\n\n node.getDevices().then(({ audioDevices: a, videoDevices: v }) => {\n setAudioDevices(a);\n setVideoDevices(v);\n });\n\n node.onCallStatus = (status: string | null) => {\n const parsedStatus = status as CallStatus | '';\n setCallStatus(parsedStatus);\n if (parsedStatus === CallStatus.ENDED || !parsedStatus) {\n setLocalStream(null);\n setRemoteStream(null);\n setIsIncoming(false);\n setCallStatus('');\n }\n };\n\n node.onLocalStream = (stream: MediaStream) => {\n setLocalStream(stream);\n const audioTracks = stream.getAudioTracks();\n setIsMicMuted(audioTracks.length === 0 || !audioTracks[0].enabled);\n const videoTracks = stream.getVideoTracks();\n setIsVideoMuted(videoTracks.length === 0 || !videoTracks[0].enabled);\n };\n\n node.onRemoteStream = (stream: MediaStream) => setRemoteStream(stream);\n\n // Listen for remote peer transceiver state via data channel\n node.onDataChannelMessage = (state: { audio_enable?: boolean; video_enable?: boolean }) => {\n if (typeof state?.audio_enable === 'boolean') {\n setIsRemoteMicMuted(!state.audio_enable);\n }\n if (typeof state?.video_enable === 'boolean') {\n setIsRemoteVideoMuted(!state.video_enable);\n }\n };\n\n // Listen for remote peer requesting to upgrade call (audio → video)\n // Pattern 2: Automatically switch UI layout to video without prompting.\n node.onUpgradeCall = () => {\n setCallType('video');\n // Note: We don't turn on our own camera automatically.\n };\n\n return () => {\n const cleanup = async () => {\n try {\n await node.endCall();\n } catch (e) { } // ignore during unmount\n };\n cleanup();\n };\n }, [client, sessionId, wasmPath, relayUrl, onIncomingCall, onCallError]);\n\n const createCall = useCallback(async (type: 'audio' | 'video', cid: string) => {\n if (!callNode) return;\n setCallType(type);\n setIsIncoming(false);\n setCallStatus(CallStatus.RINGING);\n await callNode.createCall(type, cid);\n // C1: Lifecycle callback — call started\n onCallStart?.(type, cid);\n }, [callNode, onCallStart]);\n\n const acceptCall = useCallback(async () => {\n if (callNode) await callNode.acceptCall();\n // C1: Lifecycle callback — call accepted\n onCallAccepted?.();\n }, [callNode, onCallAccepted]);\n\n const rejectCall = useCallback(async () => {\n if (callNode) await callNode.rejectCall();\n setCallStatus('');\n setIsIncoming(false);\n // C1: Lifecycle callback — call rejected\n onCallRejected?.();\n }, [callNode, onCallRejected]);\n\n const endCall = useCallback(async () => {\n if (callNode) await callNode.endCall();\n // C1: Lifecycle callback — call ended (capture duration before reset)\n const duration = callDuration;\n setCallStatus('');\n setIsIncoming(false);\n setLocalStream(null);\n setRemoteStream(null);\n onCallEnd?.(duration);\n }, [callNode, callDuration, onCallEnd]);\n\n const toggleScreenShare = useCallback(async () => {\n if (!callNode) return;\n if (isScreenSharing) {\n await callNode.stopScreenShare();\n } else {\n await callNode.startScreenShare();\n }\n }, [callNode, isScreenSharing]);\n\n const switchAudioDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchAudioDevice(deviceId);\n if (success) setSelectedAudioDeviceId(deviceId);\n }, [callNode]);\n\n const switchVideoDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchVideoDevice(deviceId);\n if (success) setSelectedVideoDeviceId(deviceId);\n }, [callNode]);\n\n const clearError = useCallback(() => setErrorMessage(null), []);\n\n const upgradeCall = useCallback(async () => {\n if (!callNode) return;\n await callNode.upgradeCall();\n setCallType('video');\n }, [callNode]);\n\n const toggleMic = useCallback(async () => {\n if (!callNode || !localStream) return;\n const newMutedState = !isMicMuted;\n await callNode.toggleMic(!newMutedState);\n setIsMicMuted(newMutedState);\n }, [callNode, localStream, isMicMuted]);\n\n const toggleVideo = useCallback(async () => {\n if (!callNode) return;\n if (localStream) {\n if (localStream.getVideoTracks().length > 0) {\n const newMutedState = !isVideoMuted;\n await callNode.toggleCamera(!newMutedState);\n setIsVideoMuted(newMutedState);\n } else {\n // One-way video case: we are in a video call but our camera is off (no track).\n // Clicking toggle video should add our camera track via requestUpgradeCall.\n // This avoids sending the UPGRADE_CALL signal to the backend again.\n await callNode.requestUpgradeCall(true);\n setIsVideoMuted(false);\n }\n }\n }, [callNode, localStream, isVideoMuted]);\n\n const value = {\n callNode,\n callStatus,\n localStream,\n remoteStream,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n createCall,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n isRemoteVideoMuted,\n upgradeCall,\n callDuration,\n };\n\n return (\n <ErmisCallContext.Provider value={value}>\n {children}\n </ErmisCallContext.Provider>\n );\n};\n\nErmisCallProvider.displayName = 'ErmisCallProvider';\n","import React from 'react';\nimport { CallStatus, type ErmisCallNode, type UserCallInfo } from '@ermis-network/ermis-chat-sdk';\n\nexport type CallContextValue = {\n callNode: ErmisCallNode | null;\n callStatus: CallStatus | '';\n localStream: MediaStream | null;\n remoteStream: MediaStream | null;\n callType: string;\n callerInfo?: UserCallInfo | undefined;\n receiverInfo?: UserCallInfo | undefined;\n isIncoming: boolean;\n createCall: (type: 'audio' | 'video', cid: string) => Promise<void>;\n acceptCall: () => Promise<void>;\n rejectCall: () => Promise<void>;\n endCall: () => Promise<void>;\n toggleMic: () => void;\n toggleVideo: () => void;\n isMicMuted: boolean;\n isVideoMuted: boolean;\n audioDevices: MediaDeviceInfo[];\n videoDevices: MediaDeviceInfo[];\n selectedAudioDeviceId: string;\n selectedVideoDeviceId: string;\n isScreenSharing: boolean;\n errorMessage: string | null;\n toggleScreenShare: () => Promise<void>;\n switchAudioDevice: (id: string) => Promise<void>;\n switchVideoDevice: (id: string) => Promise<void>;\n clearError: () => void;\n isRemoteMicMuted: boolean;\n isRemoteVideoMuted: boolean;\n upgradeCall: () => Promise<void>;\n callDuration: number;\n};\n\nexport const ErmisCallContext = React.createContext<CallContextValue | undefined>(undefined);\n","import React, { useEffect, useRef, useState, useCallback } from 'react';\nimport { useCallContext } from '../hooks/useCallContext';\nimport { Modal } from './Modal';\nimport { Avatar } from './Avatar';\nimport { CallStatus } from '@ermis-network/ermis-chat-sdk';\nimport type { ErmisCallUIProps } from '../types';\n\n/** Format seconds into MM:SS */\nconst formatDuration = (totalSeconds: number): string => {\n const m = Math.floor(totalSeconds / 60).toString().padStart(2, '0');\n const s = (totalSeconds % 60).toString().padStart(2, '0');\n return `${m}:${s}`;\n};\n\nexport const ErmisCallUI: React.FC<ErmisCallUIProps> = React.memo(({\n className,\n incomingCallTitle = (type: string) => `Incoming ${type} call`,\n outgoingCallTitle = (type: string) => `Outgoing ${type} call`,\n ongoingCallTitle = (type: string) => `Ongoing ${type} Call`,\n isCallingYouLabel = 'is calling you...',\n ringingLabel = 'Ringing...',\n rejectCallLabel = 'Reject',\n acceptCallLabel = 'Accept',\n endCallLabel = 'End Call',\n cancelLabel = 'Cancel',\n toggleMicTitle = 'Toggle Mic',\n toggleVideoTitle = 'Toggle Video',\n shareScreenTitle = 'Share Screen',\n stopScreenShareTitle = 'Stop Sharing',\n connectedLabel = 'Connected',\n audioCallBadgeLabel = 'Audio Call',\n videoCallBadgeLabel = 'Video Call',\n fullscreenTitle = 'Fullscreen',\n exitFullscreenTitle = 'Exit Fullscreen',\n upgradeCallTitle = 'Request Video Upgrade',\n suppressIncomingCalls = false,\n onCallDurationChange,\n AvatarComponent = Avatar,\n MicIcon: PropMicIcon,\n MicOffIcon: PropMicOffIcon,\n VideoIcon: PropVideoIcon,\n VideoOffIcon: PropVideoOffIcon,\n PhoneIcon: PropPhoneIcon,\n ScreenShareIcon: PropScreenShareIcon,\n ScreenShareOffIcon: PropScreenShareOffIcon,\n FullscreenIcon: PropFullscreenIcon,\n ExitFullscreenIcon: PropExitFullscreenIcon,\n UpgradeCallIcon: PropUpgradeCallIcon,\n incomingCallAudioPath = '/call_incoming.mp3',\n outgoingCallAudioPath = '/call_outgoing.mp3',\n RingingComponent: CustomRingingComponent,\n ConnectedAudioComponent: CustomConnectedAudioComponent,\n ConnectedVideoComponent: CustomConnectedVideoComponent,\n ErrorComponent: CustomErrorComponent,\n ControlsBarComponent: CustomControlsBarComponent,\n}) => {\n const {\n callStatus,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n localStream,\n remoteStream,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n upgradeCall,\n callDuration,\n } = useCallContext();\n\n const localVideoRef = useRef<HTMLVideoElement>(null);\n const remoteVideoRef = useRef<HTMLVideoElement>(null);\n const remoteAudioRef = useRef<HTMLAudioElement>(null);\n const ringingAudioRef = useRef<HTMLAudioElement>(null);\n const callContainerRef = useRef<HTMLDivElement>(null);\n\n // Fullscreen state\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n const toggleFullscreen = useCallback(() => {\n if (!callContainerRef.current) return;\n if (!document.fullscreenElement) {\n callContainerRef.current.requestFullscreen?.().catch(() => {});\n } else {\n document.exitFullscreen?.().catch(() => {});\n }\n }, []);\n\n useEffect(() => {\n const handleChange = () => setIsFullscreen(!!document.fullscreenElement);\n document.addEventListener('fullscreenchange', handleChange);\n return () => document.removeEventListener('fullscreenchange', handleChange);\n }, []);\n\n // C5: Notify consumer of duration changes\n useEffect(() => {\n if (callDuration > 0) {\n onCallDurationChange?.(callDuration);\n }\n }, [callDuration, onCallDurationChange]);\n\n useEffect(() => {\n if (localVideoRef.current && localStream) {\n localVideoRef.current.srcObject = localStream;\n }\n }, [localStream, callType, callStatus]);\n\n useEffect(() => {\n if (remoteStream) {\n if (callType === 'video' && remoteVideoRef.current) {\n remoteVideoRef.current.srcObject = remoteStream;\n }\n if (remoteAudioRef.current) {\n remoteAudioRef.current.srcObject = remoteStream;\n }\n }\n }, [remoteStream, callType, callStatus]);\n\n useEffect(() => {\n if (callStatus === CallStatus.RINGING && ringingAudioRef.current) {\n const playPromise = ringingAudioRef.current.play();\n if (playPromise !== undefined) {\n playPromise.catch((e) => console.log('ErmisChat: Audio play blocked by browser:', e));\n }\n } else if (ringingAudioRef.current) {\n ringingAudioRef.current.pause();\n ringingAudioRef.current.currentTime = 0;\n }\n }, [callStatus]);\n\n if (!callStatus && !errorMessage) return null;\n\n // C3: Suppress incoming call UI (DND mode)\n if (suppressIncomingCalls && isIncoming && callStatus === CallStatus.RINGING) return null;\n\n const isOpen = callStatus === CallStatus.RINGING || callStatus === CallStatus.CONNECTED || !!errorMessage;\n if (!isOpen) return null;\n\n const title = errorMessage ? 'Call Error' : (\n callStatus === CallStatus.RINGING\n ? (isIncoming ? incomingCallTitle(callType) : outgoingCallTitle(callType))\n : ongoingCallTitle(callType)\n );\n\n const peerInfo = isIncoming ? callerInfo : receiverInfo;\n const modalMaxWidth = callType === 'video' && callStatus === CallStatus.CONNECTED ? '720px' : '480px';\n\n // Default icons\n const FinalPhoneIcon = PropPhoneIcon || (() => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n ));\n\n const FinalVideoIcon = PropVideoIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n ));\n\n const FinalVideoOffIcon = PropVideoOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 16v1a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2m5.66 0H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10M1 1l22 22\"></path>\n </svg>\n ));\n\n const FinalMicIcon = PropMicIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"></path>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalMicOffIcon = PropMicOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"></path>\n <path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalScreenShareIcon = PropScreenShareIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <path d=\"M16 11l-4 4-4-4\"></path>\n <path d=\"M12 15V7\"></path>\n </svg>\n ));\n\n const FinalScreenShareOffIcon = PropScreenShareOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"10\"></line>\n </svg>\n ));\n\n const FinalFullscreenIcon = PropFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3\"></path>\n <path d=\"M21 8V5a2 2 0 0 0-2-2h-3\"></path>\n <path d=\"M3 16v3a2 2 0 0 0 2 2h3\"></path>\n <path d=\"M16 21h3a2 2 0 0 0 2-2v-3\"></path>\n </svg>\n ));\n\n const FinalExitFullscreenIcon = PropExitFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4 14h6v6\"></path>\n <path d=\"M20 10h-6V4\"></path>\n <path d=\"M14 10l7-7\"></path>\n <path d=\"M3 21l7-7\"></path>\n </svg>\n ));\n\n // C4: Upgrade call icon (defaults to FinalVideoIcon)\n const FinalUpgradeCallIcon = PropUpgradeCallIcon || FinalVideoIcon;\n\n /* ================================================================\n Shared Controls Bar — used by both audio and video active states\n ================================================================ */\n const renderControls = () => {\n // C6: Allow consumer to replace controls bar entirely\n if (CustomControlsBarComponent) {\n return (\n <CustomControlsBarComponent\n callType={callType}\n toggleMic={toggleMic}\n toggleVideo={toggleVideo}\n toggleScreenShare={toggleScreenShare}\n toggleFullscreen={toggleFullscreen}\n upgradeCall={upgradeCall}\n endCall={endCall}\n isMicMuted={isMicMuted}\n isVideoMuted={isVideoMuted}\n isScreenSharing={isScreenSharing}\n isFullscreen={isFullscreen}\n audioDevices={audioDevices}\n videoDevices={videoDevices}\n selectedAudioDeviceId={selectedAudioDeviceId}\n selectedVideoDeviceId={selectedVideoDeviceId}\n switchAudioDevice={switchAudioDevice}\n switchVideoDevice={switchVideoDevice}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__controls\">\n {/* Mic */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleMic}\n className={`ermis-call-ui__control-btn ${isMicMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleMicTitle}\n >\n {isMicMuted ? <FinalMicOffIcon /> : <FinalMicIcon />}\n </button>\n {audioDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedAudioDeviceId}\n onChange={(e) => switchAudioDevice(e.target.value)}\n >\n {audioDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Microphone'}</option>\n ))}\n </select>\n )}\n </div>\n\n {/* Video controls */}\n {callType === 'video' ? (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleVideo}\n className={`ermis-call-ui__control-btn ${isVideoMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleVideoTitle}\n >\n {isVideoMuted ? <FinalVideoOffIcon /> : <FinalVideoIcon />}\n </button>\n {videoDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedVideoDeviceId}\n onChange={(e) => switchVideoDevice(e.target.value)}\n >\n {videoDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Camera'}</option>\n ))}\n </select>\n )}\n </div>\n ) : (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={upgradeCall}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={upgradeCallTitle}\n >\n <FinalUpgradeCallIcon />\n </button>\n </div>\n )}\n\n {/* Screen Share */}\n {callType === 'video' && typeof navigator.mediaDevices?.getDisplayMedia === 'function' && (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleScreenShare}\n className={`ermis-call-ui__control-btn ${isScreenSharing ? 'ermis-call-ui__control-btn--active' : ''}`}\n data-tooltip={isScreenSharing ? stopScreenShareTitle : shareScreenTitle}\n >\n {isScreenSharing ? <FinalScreenShareIcon /> : <FinalScreenShareOffIcon />}\n </button>\n </div>\n )}\n\n {/* Fullscreen */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleFullscreen}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={isFullscreen ? exitFullscreenTitle : fullscreenTitle}\n >\n {isFullscreen ? <FinalExitFullscreenIcon /> : <FinalFullscreenIcon />}\n </button>\n </div>\n\n {/* Separator before end call */}\n <div className=\"ermis-call-ui__controls-separator\" />\n\n {/* End Call */}\n <button\n onClick={endCall}\n className=\"ermis-call-ui__control-btn ermis-call-ui__control-btn--danger\"\n data-tooltip={endCallLabel}\n >\n <FinalPhoneIcon />\n </button>\n </div>\n );\n };\n\n /* ================================================================\n Render ringing state\n ================================================================ */\n const renderRinging = () => {\n // C6: Allow consumer to replace ringing view entirely\n if (CustomRingingComponent) {\n return (\n <CustomRingingComponent\n peerInfo={peerInfo}\n callType={callType}\n isIncoming={isIncoming}\n acceptCall={acceptCall}\n rejectCall={rejectCall}\n endCall={endCall}\n AvatarComponent={AvatarComponent}\n isCallingYouLabel={isCallingYouLabel}\n ringingLabel={ringingLabel}\n rejectCallLabel={rejectCallLabel}\n acceptCallLabel={acceptCallLabel}\n endCallLabel={endCallLabel}\n audioCallBadgeLabel={audioCallBadgeLabel}\n videoCallBadgeLabel={videoCallBadgeLabel}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__ringing\">\n {/* Avatar with pulse rings */}\n <div className=\"ermis-call-ui__ringing-avatar\">\n <div className=\"ermis-call-ui__ringing-avatar-inner\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={88}\n />\n </div>\n </div>\n\n <h3 className=\"ermis-call-ui__ringing-name\">\n {peerInfo?.name}\n </h3>\n <p className=\"ermis-call-ui__ringing-status\">\n {isIncoming ? isCallingYouLabel : ringingLabel}\n </p>\n\n {/* Call type badge */}\n <div className=\"ermis-call-ui__type-badge\">\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n {callType === 'video' ? videoCallBadgeLabel : audioCallBadgeLabel}\n </div>\n\n {/* Action buttons */}\n <div className=\"ermis-call-ui__ringing-actions\">\n {isIncoming ? (\n <>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={rejectCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n <FinalPhoneIcon />\n </button>\n <span className=\"ermis-call-ui__action-label\">{rejectCallLabel}</span>\n </div>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={acceptCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--accept\"\n >\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n </button>\n <span className=\"ermis-call-ui__action-label\">{acceptCallLabel}</span>\n </div>\n </>\n ) : (\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={endCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n <FinalPhoneIcon />\n </button>\n <span className=\"ermis-call-ui__action-label\">{endCallLabel}</span>\n </div>\n )}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render connected state\n ================================================================ */\n const renderConnected = () => {\n if (callType === 'video') {\n // C6: Allow consumer to replace connected video view\n if (CustomConnectedVideoComponent) {\n return (\n <CustomConnectedVideoComponent\n localVideoRef={localVideoRef}\n remoteVideoRef={remoteVideoRef}\n isRemoteMicMuted={isRemoteMicMuted}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__video-container\">\n <video\n ref={remoteVideoRef}\n autoPlay\n playsInline\n className=\"ermis-call-ui__video-remote\"\n />\n <div className=\"ermis-call-ui__video-local\">\n <video\n ref={localVideoRef}\n autoPlay\n playsInline\n muted\n className=\"ermis-call-ui__video-local-stream\"\n />\n </div>\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge\">\n <FinalMicOffIcon />\n </div>\n )}\n {/* Glassmorphism controls overlay */}\n <div className=\"ermis-call-ui__video-controls-overlay\">\n {renderControls()}\n </div>\n </div>\n </div>\n );\n }\n\n // Audio call\n // C6: Allow consumer to replace connected audio view\n if (CustomConnectedAudioComponent) {\n return (\n <CustomConnectedAudioComponent\n peerInfo={peerInfo}\n callDuration={callDuration}\n isRemoteMicMuted={isRemoteMicMuted}\n AvatarComponent={AvatarComponent}\n connectedLabel={connectedLabel}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__audio-container\">\n <div className=\"ermis-call-ui__audio-avatar-wrapper\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={100}\n />\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge ermis-call-ui__remote-muted-badge--audio\">\n <FinalMicOffIcon />\n </div>\n )}\n </div>\n <h3 className=\"ermis-call-ui__active-name\">\n {peerInfo?.name}\n </h3>\n\n {/* Status + Timer */}\n <div className=\"ermis-call-ui__active-status\">\n <span className=\"ermis-call-ui__active-status-dot\" />\n <span>{connectedLabel}</span>\n <span className=\"ermis-call-ui__timer\">\n {formatDuration(callDuration)}\n </span>\n </div>\n\n {/* Audio wave visualizer */}\n <div className=\"ermis-call-ui__audio-waves\">\n {Array.from({ length: 9 }).map((_, i) => (\n <span key={i} className=\"ermis-call-ui__audio-wave-bar\" />\n ))}\n </div>\n\n <audio ref={remoteAudioRef} autoPlay className=\"ermis-call-ui__audio--hidden\" />\n\n {/* Controls bar */}\n {renderControls()}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render error state\n ================================================================ */\n const renderError = () => {\n if (!errorMessage) return null;\n\n // C6: Allow consumer to replace error view\n if (CustomErrorComponent) {\n return (\n <CustomErrorComponent\n errorMessage={errorMessage}\n clearError={clearError}\n cancelLabel={cancelLabel}\n PhoneIcon={FinalPhoneIcon}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__error\">\n <div className=\"ermis-call-ui__error-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--ermis-color-danger)\" strokeWidth=\"2\" width=\"56\" height=\"56\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n </div>\n <p className=\"ermis-call-ui__error-text\">{errorMessage}</p>\n <button\n className=\"ermis-call-ui__error-dismiss\"\n onClick={clearError}\n >\n <FinalPhoneIcon /> {cancelLabel}\n </button>\n </div>\n );\n };\n\n return (\n <Modal isOpen={isOpen} onClose={endCall} title={title} hideCloseButton closeOnOutsideClick={false} maxWidth={modalMaxWidth}>\n <div className={`ermis-call-ui ${isFullscreen ? 'ermis-call-ui--fullscreen' : ''}${className ? ` ${className}` : ''}`} ref={callContainerRef}>\n {/* Ringing audio */}\n {(incomingCallAudioPath || outgoingCallAudioPath) && (\n <audio\n ref={ringingAudioRef}\n src={isIncoming ? incomingCallAudioPath : outgoingCallAudioPath}\n loop\n className=\"ermis-call-ui__audio--hidden\"\n />\n )}\n\n {/* ============ ERROR STATE ============ */}\n {errorMessage && renderError()}\n\n {/* ============ RINGING STATE ============ */}\n {!errorMessage && callStatus === CallStatus.RINGING && renderRinging()}\n\n {/* ============ CONNECTED STATE ============ */}\n {!errorMessage && callStatus === CallStatus.CONNECTED && renderConnected()}\n </div>\n </Modal>\n );\n});\n\nErmisCallUI.displayName = 'ErmisCallUI';\n","import { useContext } from 'react';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\n\nexport const useCallContext = () => {\n const context = useContext(ErmisCallContext);\n if (context === undefined) {\n throw new Error('useCallContext must be used within an ErmisCallProvider');\n }\n return context;\n};\n","import React, { useEffect } from 'react';\nimport type { ModalProps } from '../types';\n\nexport const Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n children,\n footer,\n maxWidth = '480px',\n hideCloseButton = false,\n closeOnOutsideClick = true,\n}) => {\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen) onClose();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"ermis-modal-overlay\" onClick={closeOnOutsideClick ? onClose : undefined}>\n <div \n className=\"ermis-modal-content\" \n style={{ maxWidth }} \n onClick={e => e.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <div className=\"ermis-modal-header\">\n {title ? (\n typeof title === 'string' ? <h3>{title}</h3> : title\n ) : <div />}\n {!hideCloseButton && (\n <button className=\"ermis-modal-close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n )}\n </div>\n )}\n\n <div className=\"ermis-modal-body\">\n {children}\n </div>\n\n {footer && (\n <div className=\"ermis-modal-footer\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n","import React, { useMemo, useState } from 'react';\nimport { MediaLightbox } from './MediaLightbox';\nimport type { AvatarProps } from '../types';\n\nexport type { AvatarProps } from '../types';\n\n/**\n * Extracts 1–2 initials from a name.\n */\nfunction getInitials(name?: string): string {\n if (!name) return '?';\n if (name.startsWith('0x')) return '0x';\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n }\n return parts[0][0].toUpperCase();\n}\n\n/**\n * Avatar component with image or initial fallback.\n */\nexport const Avatar: React.FC<AvatarProps> = React.memo(({\n image,\n name,\n size = 36,\n className,\n disableLightbox,\n}) => {\n const [isLoaded, setIsLoaded] = useState(false);\n const [hasError, setHasError] = useState(false);\n const [isLightboxOpen, setIsLightboxOpen] = useState(false);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Reset state if image URL changes\n React.useEffect(() => {\n if (image) {\n setHasError(false);\n if (imgRef.current?.complete) {\n setIsLoaded(true);\n } else {\n setIsLoaded(false);\n }\n }\n }, [image]);\n\n const initials = useMemo(() => getInitials(name), [name]);\n\n const wrapperStyle = useMemo<React.CSSProperties>(() => ({\n width: size,\n height: size,\n minWidth: size,\n position: 'relative',\n borderRadius: '100%', /* Or var(--ermis-radius-full) */\n overflow: 'hidden',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: image && !hasError && !disableLightbox ? 'pointer' : undefined,\n }), [size, image, hasError, disableLightbox]);\n\n const contentStyle = useMemo<React.CSSProperties>(() => ({\n width: '100%',\n height: '100%',\n fontSize: size * 0.4,\n lineHeight: 1,\n }), [size]);\n\n const handleAvatarClick = React.useCallback((e: React.MouseEvent) => {\n if (image && !hasError && !disableLightbox) {\n e.stopPropagation();\n e.preventDefault();\n setIsLightboxOpen(true);\n }\n }, [image, hasError, disableLightbox]);\n\n return (\n <>\n <div \n className={`ermis-avatar-wrapper${className ? ` ${className}` : ''}`} \n style={wrapperStyle}\n onClick={handleAvatarClick}\n >\n {/* 1. Underlying Fallback (Placeholder) */}\n <div\n className=\"ermis-avatar ermis-avatar--fallback\"\n style={contentStyle}\n title={name}\n >\n {initials}\n </div>\n\n {/* 2. Actual Image (Lazy, Fades in natively using CSS opacity) */}\n {image && !hasError && (\n <img\n ref={imgRef}\n className=\"ermis-avatar__img\"\n src={image}\n alt={name || 'Avatar'}\n loading=\"lazy\"\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasError(true)}\n style={{\n ...contentStyle,\n position: 'absolute',\n top: 0,\n left: 0,\n opacity: isLoaded ? 1 : 0,\n transition: 'opacity 0.3s ease-in-out',\n objectFit: 'cover',\n }}\n />\n )}\n </div>\n\n {isLightboxOpen && image && !hasError && (\n <MediaLightbox\n items={[{ type: 'image', src: image, alt: name || 'Avatar' }]}\n isOpen={isLightboxOpen}\n onClose={() => setIsLightboxOpen(false)}\n />\n )}\n </>\n );\n});\n\nAvatar.displayName = 'Avatar';\n","import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport ReactDOM from 'react-dom';\nimport { preloadImage } from '../utils';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { MediaLightboxProps } from '../types';\n\n/** Extract a reasonable filename from a URL or alt text */\nconst getFilename = (src: string, alt?: string): string => {\n if (alt) return alt;\n try {\n const pathname = new URL(src).pathname;\n const segments = pathname.split('/');\n return segments[segments.length - 1] || 'download';\n } catch {\n return 'download';\n }\n};\n\n/**\n * MediaLightbox – full-screen overlay for viewing images & videos.\n * Supports prev/next navigation, keyboard controls, and image zoom.\n * Renders via React portal into document.body.\n */\nexport const MediaLightbox: React.FC<MediaLightboxProps> = React.memo(({\n items,\n initialIndex = 0,\n isOpen,\n onClose,\n}) => {\n const [currentIndex, setCurrentIndex] = useState(initialIndex);\n const [zoom, setZoom] = useState(1);\n const [pan, setPan] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const dragStart = useRef({ x: 0, y: 0 });\n const panStart = useRef({ x: 0, y: 0 });\n const videoRef = useRef<HTMLVideoElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Reset state when opening or when items change\n useEffect(() => {\n if (isOpen) {\n setCurrentIndex(initialIndex);\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }\n }, [isOpen, initialIndex]);\n\n // Preload adjacent images\n useEffect(() => {\n if (!isOpen) return;\n const preloadIdx = [currentIndex - 1, currentIndex + 1];\n preloadIdx.forEach(idx => {\n if (idx >= 0 && idx < items.length && items[idx].type === 'image') {\n preloadImage(items[idx].src);\n }\n });\n }, [isOpen, currentIndex, items]);\n\n // Pause video when navigating away or closing\n useEffect(() => {\n return () => {\n if (videoRef.current) {\n videoRef.current.pause();\n }\n };\n }, [currentIndex]);\n\n // Lock body scroll when open\n useEffect(() => {\n if (isOpen) {\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => { document.body.style.overflow = prev; };\n }\n }, [isOpen]);\n\n const goTo = useCallback((idx: number) => {\n if (videoRef.current) videoRef.current.pause();\n setCurrentIndex(idx);\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }, []);\n\n const goPrev = useCallback(() => {\n if (currentIndex > 0) goTo(currentIndex - 1);\n }, [currentIndex, goTo]);\n\n const goNext = useCallback(() => {\n if (currentIndex < items.length - 1) goTo(currentIndex + 1);\n }, [currentIndex, items.length, goTo]);\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return;\n const handleKey = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'Escape':\n onClose();\n break;\n case 'ArrowLeft':\n goPrev();\n break;\n case 'ArrowRight':\n goNext();\n break;\n }\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose, goPrev, goNext]);\n\n // Double-click zoom toggle (image only)\n const handleDoubleClick = useCallback(() => {\n const current = items[currentIndex];\n if (current?.type !== 'image') return;\n\n if (zoom === 1) {\n setZoom(2);\n } else {\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }\n }, [currentIndex, items, zoom]);\n\n // Wheel zoom (image only)\n const handleWheel = useCallback((e: React.WheelEvent) => {\n const current = items[currentIndex];\n if (current?.type !== 'image') return;\n e.preventDefault();\n\n setZoom(prev => {\n const next = prev - e.deltaY * 0.002;\n const clamped = Math.max(1, Math.min(3, next));\n if (clamped === 1) setPan({ x: 0, y: 0 });\n return clamped;\n });\n }, [currentIndex, items]);\n\n // Mouse drag for panning (image zoomed)\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (zoom <= 1) return;\n e.preventDefault();\n setIsDragging(true);\n dragStart.current = { x: e.clientX, y: e.clientY };\n panStart.current = { ...pan };\n }, [zoom, pan]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n const dx = e.clientX - dragStart.current.x;\n const dy = e.clientY - dragStart.current.y;\n setPan({ x: panStart.current.x + dx, y: panStart.current.y + dy });\n }, [isDragging]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n // Click on backdrop closes\n const handleBackdropClick = useCallback((e: React.MouseEvent) => {\n if (e.target === containerRef.current) {\n onClose();\n }\n }, [onClose]);\n\n const { client } = useChatClient();\n\n const currentItem = items[currentIndex];\n const hasMultiple = items.length > 1;\n\n const handleDownload = useCallback(async () => {\n if (!currentItem) return;\n const filename = getFilename(currentItem.src, currentItem.alt);\n\n try {\n const blob = await client.downloadMedia(currentItem.src);\n const urlBlob = window.URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = urlBlob;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n window.URL.revokeObjectURL(urlBlob);\n } catch {\n window.open(currentItem.src, '_blank', 'noopener,noreferrer');\n }\n }, [client, currentItem]);\n\n const content = useMemo(() => {\n if (!currentItem) return null;\n\n if (currentItem.type === 'video') {\n return (\n <video\n ref={videoRef}\n className=\"ermis-lightbox__video\"\n src={currentItem.src}\n poster={currentItem.posterSrc}\n controls\n autoPlay\n preload=\"metadata\"\n onClick={(e) => e.stopPropagation()}\n />\n );\n }\n\n const imgStyle: React.CSSProperties = {\n transform: `scale(${zoom}) translate(${pan.x / zoom}px, ${pan.y / zoom}px)`,\n cursor: zoom > 1 ? (isDragging ? 'grabbing' : 'grab') : 'default',\n };\n\n return (\n <img\n className={`ermis-lightbox__image${zoom > 1 ? ' ermis-lightbox__image--zoomed' : ''}`}\n src={currentItem.src}\n alt={currentItem.alt || ''}\n style={imgStyle}\n draggable={false}\n onDoubleClick={handleDoubleClick}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n onClick={(e) => e.stopPropagation()}\n />\n );\n }, [currentItem, zoom, pan, isDragging, handleDoubleClick, handleMouseDown, handleMouseMove, handleMouseUp]);\n\n if (!isOpen || !currentItem) return null;\n\n return ReactDOM.createPortal(\n <div className=\"ermis-lightbox\" onWheel={handleWheel}>\n <div className=\"ermis-lightbox__backdrop\" />\n\n {/* Header: counter + actions */}\n <div className=\"ermis-lightbox__header\">\n {hasMultiple && (\n <span className=\"ermis-lightbox__counter\">\n {currentIndex + 1} / {items.length}\n </span>\n )}\n <div className=\"ermis-lightbox__actions\">\n <button\n className=\"ermis-lightbox__action-btn\"\n onClick={handleDownload}\n aria-label=\"Download\"\n title=\"Download\"\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n <button\n className=\"ermis-lightbox__action-btn\"\n onClick={onClose}\n aria-label=\"Close\"\n title=\"Close\"\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Main content area */}\n <div\n ref={containerRef}\n className=\"ermis-lightbox__content\"\n onClick={handleBackdropClick}\n >\n {/* Prev button */}\n {hasMultiple && currentIndex > 0 && (\n <button\n className=\"ermis-lightbox__nav ermis-lightbox__nav--prev\"\n onClick={(e) => { e.stopPropagation(); goPrev(); }}\n aria-label=\"Previous\"\n >\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n )}\n\n {/* Media */}\n {content}\n\n {/* Next button */}\n {hasMultiple && currentIndex < items.length - 1 && (\n <button\n className=\"ermis-lightbox__nav ermis-lightbox__nav--next\"\n onClick={(e) => { e.stopPropagation(); goNext(); }}\n aria-label=\"Next\"\n >\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Filename */}\n {currentItem.alt && (\n <div className=\"ermis-lightbox__filename\">{currentItem.alt}</div>\n )}\n </div>,\n document.body\n );\n});\nMediaLightbox.displayName = 'MediaLightbox';\n","import type { MentionMember } from './types';\nimport type { Attachment, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Format a Date or date-string to a short time string (HH:MM).\n */\nexport function formatTime(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\n/**\n * Format a date as \"HH:MM, Today\", \"HH:MM, Yesterday\", or \"HH:MM, MM/DD/YYYY\".\n */\nexport function formatReadTimestamp(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n const time = d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\n if (diffDays === 0) return `${time}, Today`;\n if (diffDays === 1) return `${time}, Yesterday`;\n const mm = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n const yyyy = d.getFullYear();\n return `${time}, ${mm}/${dd}/${yyyy}`;\n}\n\n/**\n * Return a YYYY-M-D key for date comparison (used by date separators).\n */\nexport function getDateKey(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;\n}\n\n/**\n * Format a date into a human-friendly label (Today / Yesterday / full date).\n */\nexport function formatDateLabel(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n return d.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n}\n\n/**\n * Get the user id from a message, checking multiple possible sources.\n */\nexport function getMessageUserId(message: FormatMessageResponse): string {\n return message.user?.id || message.user_id || '';\n}\n\n/**\n * Replace @user_id with @UserName for plain text previews.\n * Returns the formatted string.\n */\nexport function replaceMentionsForPreview(\n text: string,\n message: FormatMessageResponse | { mentioned_users?: string[]; mentioned_all?: boolean },\n userMap: Record<string, string>,\n renderWrapper?: (userId: string, name: string) => string\n): string {\n const mentionedUsers: string[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, nothing to replace\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return text;\n }\n\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userId of mentionedUsers) {\n if (!userId) continue;\n const name = userMap[userId] ?? userId;\n replacements.push({\n pattern: `@${userId}`,\n label: renderWrapper ? renderWrapper(userId, name) : `@${name}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({\n pattern: '@all',\n label: renderWrapper ? renderWrapper('__all__', 'all') : '@all'\n });\n }\n\n if (replacements.length === 0) return text;\n\n // Escape special regex characters in the patterns\n const escaped = replacements.map((r) => r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n // Map pattern back to label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return text.replace(regex, (match) => patternToLabel.get(match) || match);\n}\n\n/**\n * Common helper to build a dictionary of User ID -> Display Name\n * from the channel state, used for rendering Mentions and System logs.\n */\nexport function buildUserMap(channelState: any): Record<string, string> {\n const map: Record<string, string> = {};\n const members = channelState?.members;\n if (members && typeof members === 'object') {\n for (const [id, member] of Object.entries<any>(members)) {\n map[id] = member?.user?.name || member?.user_id || id;\n }\n }\n return map;\n}\n\n/**\n * Move caret to the very end of a contenteditable element.\n */\nexport function moveCaretToEnd(el: HTMLElement) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Move caret immediately after a specific DOM node.\n */\nexport function moveCaretAfterNode(node: Node) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Checks if a given attachment represents user-managed media (e.g., photo, video, text file, voice)\n * as opposed to backend-injected automated system cards (like linkPreviews or slash commands).\n */\nexport function isUserManagedAttachment(attachment: Attachment): boolean {\n const type = attachment.type || 'file';\n return ['image', 'video', 'file', 'voiceRecording'].includes(type);\n}\n\n/**\n * Lightweight in-memory image preloader.\n */\nconst preloadedUrls = new Set<string>();\nconst MAX_CACHE_SIZE = 500;\n\nexport function preloadImage(url: string): void {\n if (!url || preloadedUrls.has(url)) return;\n\n if (preloadedUrls.size >= MAX_CACHE_SIZE) {\n const first = preloadedUrls.values().next().value;\n if (first) preloadedUrls.delete(first);\n }\n\n const img = new Image();\n img.src = url;\n preloadedUrls.add(url);\n}\n\nexport function isImagePreloaded(url: string): boolean {\n return preloadedUrls.has(url);\n}\n\n/**\n * Format bytes into a human-readable file size (e.g. \"1.2 MB\").\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n\n/**\n * Format a date string into a relative label:\n * \"Today\", \"Yesterday\", \"Xd ago\", or \"Mon DD\" / \"Mon DD, YYYY\".\n */\nexport function formatRelativeDate(dateStr: string): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined });\n}\n\n/**\n * Get a cleaned display name from a raw file_name.\n * Strips UUID-heavy prefixes that the API sometimes prepends.\n */\nexport function getDisplayName(fileName: string): string {\n const parts = fileName.split('-');\n if (parts.length > 5) {\n const ext = fileName.split('.').pop() || '';\n return `file.${ext}`;\n }\n return fileName;\n}\n\n/**\n * Extract the hostname from a URL string. Returns the original string on error.\n */\nexport function extractDomain(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n","import { useContext } from 'react';\nimport { ChatContext } from '../context/ChatProvider';\nimport type { ChatContextValue } from '../context/ChatProvider';\n\nexport const useChatClient = (): ChatContextValue => {\n const ctx = useContext(ChatContext);\n if (!ctx) {\n throw new Error('useChatClient must be used within a ChatProvider');\n }\n return ctx;\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport type { UseChannelReturn } from '../types';\n\nexport type { UseChannelReturn } from '../types';\n\nexport const useChannel = (): UseChannelReturn => {\n const { activeChannel } = useChatClient();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n return {\n channel: activeChannel,\n loading,\n error,\n };\n};\n","import { useEffect, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isDirectChannel } from '../channelTypeUtils';\nimport { isPendingMember } from '../channelRoleUtils';\n\n/**\n * Subscribes to real-time events and keeps the channel list in sync:\n *\n * 1. `message.new` → moves channel to top, auto-calls `markRead()` if\n * the channel is currently active\n * 2. `message.read` → triggers re-render so the unread badge disappears\n *\n * The SDK already mutates `channel.state.latestMessages` and\n * `channel.state.unreadCount` before our listener fires, so we only\n * need to re-order / flush the React state.\n */\nexport function useChannelListUpdates(\n channels: Channel[],\n setChannels: React.Dispatch<React.SetStateAction<Channel[]>>,\n): void {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n\n // Ref to always have the latest activeChannel without re-subscribing\n const activeChannelRef = useRef(activeChannel);\n activeChannelRef.current = activeChannel;\n\n useEffect(() => {\n // --- message.new: re-sort + auto mark-read ---\n const handleNewMessage = (event: Event) => {\n const eventCid = event.cid;\n if (!eventCid) return;\n\n // If the new message is on the active channel and from someone else,\n // mark it as read immediately so unreadCount resets to 0.\n // Skip markRead if the current user is banned, blocked, or pending in that channel.\n const active = activeChannelRef.current;\n if (active?.cid === eventCid && event.user?.id !== client.userID) {\n const isBannedInActive = Boolean(active.state?.membership?.banned);\n const isBlockedInActive = isDirectChannel(active) && Boolean(active.state?.membership?.blocked);\n const isPendingActive = isPendingMember(active.state?.membership?.channel_role as string);\n\n if (!isBannedInActive && !isBlockedInActive && !isPendingActive) {\n active.markRead().catch(() => {\n // silently ignore mark-read errors\n });\n }\n }\n\n setChannels((prev) => {\n const idx = prev.findIndex((ch) => ch.cid === eventCid);\n if (idx <= 0) {\n // Already at top or not found — just create a new reference\n return idx === 0 ? [...prev] : prev;\n }\n\n const channel = prev[idx];\n\n // Don't move banned channels to the top\n if (channel.state?.membership?.banned) {\n return [...prev];\n }\n\n // Move channel to the top\n const updated = [...prev];\n const [ch] = updated.splice(idx, 1);\n updated.unshift(ch);\n return updated;\n });\n };\n\n // --- channel.deleted: remove from list and reset active ---\n const handleChannelDeleted = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n if (!eventCid) return;\n\n if (activeChannelRef.current?.cid === eventCid) {\n setActiveChannel(null);\n }\n\n setChannels((prev) => prev.filter((ch) => ch.cid !== eventCid));\n };\n\n // --- member.removed / notification.invite_rejected: remove from list if it's current user ---\n const handleMemberRemoved = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n // channel_id is often used in notification.* events instead of .cid directly\n const normalizedCid = eventCid\n ? eventCid\n : (event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined;\n\n if (!normalizedCid) return;\n\n const removedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n\n // If the current user was removed or rejected the invite, remove the channel from their list\n if (removedUserId === client.userID) {\n if (activeChannelRef.current?.cid === normalizedCid) {\n setActiveChannel(null);\n }\n setChannels((prev) => prev.filter((ch) => ch.cid !== normalizedCid));\n }\n // Note: We don't trigger a global global re-render here if someone else is removed.\n // Individual ChannelRow components handle UI updates (e.g., via channel.updated or member.removed events locally).\n };\n\n // --- channel.created: fetch channel details and prepend to list ---\n const handleChannelCreated = async (event: Event, forceWatch: boolean = false) => {\n const type = event.channel?.type || (event as Record<string, unknown>).channel_type;\n const id = event.channel?.id || (event as Record<string, unknown>).channel_id;\n const cid = event.channel?.cid || event.cid || `${type}:${id}`;\n\n if (!type || !id) return;\n\n try {\n // Initialize or retrieve channel instance from SDK cache\n const channelInstance = client.channel(type as string, id as string);\n\n // If this is a member.added event (where event.member belongs to the current user),\n // we optimistically inject the membership so it instantly jumps into pending invites!\n // We DO NOT do this for channel.created, because in channel.created, event.member is the creator (owner).\n if (!forceWatch && event.type === 'member.added' && event.member && channelInstance.state) {\n channelInstance.state.membership = {\n ...channelInstance.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n\n // If the caller requested an explicit api call (e.g. for channel.created)\n if (forceWatch && !channelInstance.initialized) {\n await channelInstance.watch().catch((err) => console.error('Failed to watch channel:', err));\n }\n\n setChannels((prev) => {\n // Double check to prevent duplicates after async pause\n if (prev.some((c) => c.cid === cid)) {\n return prev;\n }\n return [channelInstance, ...prev];\n });\n\n // Loop wait for the core SDK to finish populating the local state from its own watch\n if (!channelInstance.initialized) {\n let attempts = 0;\n const checkInitialized = setInterval(() => {\n attempts++;\n if (channelInstance.initialized || attempts > 60 /* 3s max */) {\n clearInterval(checkInitialized);\n if (channelInstance.initialized) {\n // Force useMemo in ChannelList to recalculate classification (invite vs regular) just in case\n setChannels((p) => [...p]);\n // Manually synthesize a channel.updated event to bust the React.memo inside ChannelItem\n const clientObj = channelInstance.getClient();\n if ('dispatchEvent' in clientObj && typeof clientObj.dispatchEvent === 'function') {\n (clientObj.dispatchEvent as Function)({\n type: 'channel.updated',\n cid: channelInstance.cid,\n channel: channelInstance.data,\n });\n }\n }\n }\n }, 50);\n }\n } catch (err) {\n console.error('Failed to watch newly created channel:', err);\n }\n };\n\n // --- member.added / notification.added_to_channel: fetch if current user is added/invited ---\n const handleMemberAdded = async (event: Event) => {\n const addedUserId = event.member?.user_id || event.member?.user?.id;\n // If the current user was invited or added, fetch the channel (NO API duplication)\n if (addedUserId === client.userID) {\n await handleChannelCreated(event, false);\n }\n };\n\n // --- notification.invite_accepted: force re-grouping ---\n const handleMemberUpdated = (event: Event) => {\n const updatedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n if (updatedUserId === client.userID) {\n setChannels((prev) => {\n // Defensively mutate the channel's membership before grouping logic runs\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined);\n\n if (eventCid && event.member) {\n const targetChannel = prev.find((c) => c.cid === eventCid);\n // We forcefully map the updated incoming member data into the static channel representation\n if (targetChannel && targetChannel.state) {\n targetChannel.state.membership = {\n ...targetChannel.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n }\n\n return [...prev]; // Force react map to regenerate\n });\n }\n };\n\n // --- channel.topic.enabled / disabled / created / channel.pinned / channel.unpinned: force re-render so ChannelList toggles Accordion UI, inserts new topic, or updates pinned channels ---\n const handleGenericUpdate = (event: Event) => {\n setChannels((prev) => [...prev]);\n };\n\n const sub1 = client.on('message.new', handleNewMessage);\n const sub2 = client.on('channel.deleted', handleChannelDeleted);\n const sub3 = client.on('member.removed', handleMemberRemoved);\n const sub4 = client.on('channel.created', (event) => handleChannelCreated(event, true));\n const sub5 = client.on('member.added', handleMemberAdded);\n const sub6 = client.on('notification.added_to_channel', handleMemberAdded);\n const sub7 = client.on('notification.invite_rejected', handleMemberRemoved);\n const sub8 = client.on('notification.invite_accepted', handleMemberUpdated);\n const sub9 = client.on('channel.topic.enabled', handleGenericUpdate);\n const sub10 = client.on('channel.topic.disabled', handleGenericUpdate);\n const sub11 = client.on('channel.topic.created', handleGenericUpdate);\n const sub12 = client.on('channel.pinned', handleGenericUpdate);\n const sub13 = client.on('channel.unpinned', handleGenericUpdate);\n const sub14 = client.on('notification.invite_messaging_skipped', handleMemberUpdated);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n };\n }, [client, setChannels, setActiveChannel]);\n}\n","import type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n// ─── Group Channel Types ───────────────────────────\n// Types that behave like group/team channels (roles, capabilities, settings, topics)\nconst GROUP_CHANNEL_TYPES = new Set(['team', 'meeting']);\n\n// ─── Direct Channel Types ──────────────────────────\n// Types that behave like 1-on-1 direct messaging (block/unblock)\nconst DIRECT_CHANNEL_TYPES = new Set(['messaging']);\n\n// ─── Semantic Helpers ──────────────────────────────\n\n/** Channel supports group features: roles, capabilities, settings, topics, edit, delete */\nexport function isGroupChannel(channel: Channel | null | undefined): boolean {\n return channel ? GROUP_CHANNEL_TYPES.has(channel.type) : false;\n}\n\n/** Channel is a direct (1-on-1) conversation: block/unblock, no roles */\nexport function isDirectChannel(channel: Channel | null | undefined): boolean {\n return channel ? DIRECT_CHANNEL_TYPES.has(channel.type) : false;\n}\n\n/** Channel is a topic (sub-channel of a group channel) */\nexport function isTopicChannel(channel: Channel | null | undefined): boolean {\n return channel ? (channel.type === 'topic' || Boolean(channel.data?.parent_cid)) : false;\n}\n\n/** Channel is a public group that users can join without invite */\nexport function isPublicGroupChannel(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && Boolean(channel?.data?.public);\n}\n\n/** The proxy \"general\" channel of a topics-enabled group */\nexport function isGeneralProxy(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && channel?.data?.name === 'general';\n}\n\n/** Channel has topics feature enabled */\nexport function hasTopicsEnabled(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && Boolean(channel?.data?.topics_enabled);\n}\n\n/** Whether blocked state is relevant for this channel type */\nexport function supportsBlocking(channel: Channel | null | undefined): boolean {\n return isDirectChannel(channel);\n}\n","import type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from './channelTypeUtils';\n\nexport const CHANNEL_ROLES = {\n OWNER: 'owner',\n MODERATOR: 'moder',\n MEMBER: 'member',\n PENDING: 'pending',\n SKIPPED: 'skipped',\n} as const;\n\nexport type ChannelRole = typeof CHANNEL_ROLES[keyof typeof CHANNEL_ROLES] | string;\n\n/** Checks if the user is in a pending state */\nexport function isPendingMember(role?: string): boolean {\n return role === CHANNEL_ROLES.PENDING;\n}\n\n/** Checks if the user is in a skipped state (skipped a direct message invite) */\nexport function isSkippedMember(role?: string): boolean {\n return role === CHANNEL_ROLES.SKIPPED;\n}\n\n/** Checks if the user has management permissions (owner or moderator) */\nexport function canManageChannel(role?: string): boolean {\n return role === CHANNEL_ROLES.OWNER || role === CHANNEL_ROLES.MODERATOR;\n}\n\n/** Determines if the current user has the permission to remove a specific target member */\nexport function canRemoveTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n const isTargetRemovable =\n targetRole === CHANNEL_ROLES.MEMBER ||\n targetRole === CHANNEL_ROLES.PENDING ||\n (currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MODERATOR);\n \n return canManageChannel(currentUserRole) && isTargetRemovable;\n}\n\n/** Determines if the current user has the permission to ban a specific target member */\nexport function canBanTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return canRemoveTargetMember(currentUserRole, targetRole) && targetRole !== CHANNEL_ROLES.PENDING;\n}\n\n/** Determines if the current user has the permission to promote a member to moderator */\nexport function canPromoteTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MEMBER;\n}\n\n/** Determines if the current user has the permission to demote a moderator to simple member */\nexport function canDemoteTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MODERATOR;\n}\n\n/** Checks if the user is an owner of the channel */\nexport function isOwnerMember(role?: string): boolean {\n return role === CHANNEL_ROLES.OWNER;\n}\n\n/**\n * Checks if a direct channel represents a \"friend\" relationship:\n * both members must have the 'owner' channel_role.\n */\nexport function isFriendChannel(\n channel: Channel | null | undefined,\n targetUserId: string,\n currentUserId: string,\n): boolean {\n if (!channel || !isDirectChannel(channel)) return false;\n const targetMember = channel.state?.members?.[targetUserId];\n const currentMember = channel.state?.members?.[currentUserId];\n return isOwnerMember(targetMember?.channel_role as string)\n && isOwnerMember(currentMember?.channel_role as string);\n}\n","import { useEffect, useState } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n/**\n * Custom hook to abstract real-time row-level updates for a single channel.\n * Manages the local unread count, last message preview, and banned status for the channel row in the list.\n */\nexport function useChannelRowUpdates(channel: Channel, currentUserId?: string) {\n // Track banned state for the current user in this channel\n const [isBannedInChannel, setIsBannedInChannel] = useState(() => Boolean(channel.state?.membership?.banned));\n const [isBlockedInChannel, setIsBlockedInChannel] = useState(() => {\n if (!isDirectChannel(channel)) return false;\n return Boolean(channel.state?.membership?.blocked);\n });\n\n // Force re-render when messages, members, or read state changes\n const [updateCount, setUpdateCount] = useState(0);\n\n useEffect(() => {\n setIsBannedInChannel(Boolean(channel.state?.membership?.banned));\n setIsBlockedInChannel(\n isDirectChannel(channel) ? Boolean(channel.state?.membership?.blocked) : false\n );\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(true);\n }\n };\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(false);\n }\n };\n\n const handleUpdate = () => setUpdateCount((c) => c + 1);\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n const sub3 = channel.on('message.new', handleUpdate);\n const sub4 = channel.on('message.read', handleUpdate);\n const sub5 = channel.on('message.updated', handleUpdate);\n const sub6 = channel.on('message.deleted', handleUpdate);\n const sub7 = channel.on('channel.updated', handleUpdate);\n const sub8 = channel.on('member.added', handleUpdate);\n const sub9 = channel.on('member.removed', handleUpdate);\n\n // Blocked state (messaging channels only)\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(true);\n }\n };\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(false);\n }\n };\n const sub10 = channel.on('member.blocked', handleBlocked);\n const sub11 = channel.on('member.unblocked', handleUnblocked);\n const sub12 = channel.on('channel.topic.created', handleUpdate);\n const sub13 = channel.on('channel.pinned', handleUpdate);\n const sub14 = channel.on('channel.unpinned', handleUpdate);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBannedInChannel, isBlockedInChannel, updateCount };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Hook that tracks whether the current user is banned in the given channel.\n *\n * Reads the initial value from `channel.state.membership.banned` and subscribes\n * to `member.banned` / `member.unbanned` WebSocket events for real-time updates.\n * If the channel is a topic, it also synchronizes with the parent channel's ban state.\n *\n * Only triggers a re-render when the *current user* is the target of the event.\n */\nexport function useBannedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBanned, setIsBanned] = useState<boolean>(() => {\n if (!channel) return false;\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n return Boolean(channel.state?.membership?.banned || parentChannel?.state?.membership?.banned);\n });\n\n useEffect(() => {\n if (!channel) {\n setIsBanned(false);\n return;\n }\n\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n\n // Sync initial state when channel changes\n setIsBanned(Boolean(channel.state?.membership?.banned || parentChannel?.state?.membership?.banned));\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBanned(true);\n }\n };\n\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n const eventCid = event.cid || (event.channel_type ? `${event.channel_type}:${event.channel_id}` : undefined);\n let cBanned = Boolean(channel.state?.membership?.banned);\n let pBanned = Boolean(parentChannel?.state?.membership?.banned);\n \n if (eventCid === channel.cid) cBanned = false;\n if (parentChannel && eventCid === parentChannel.cid) pBanned = false;\n \n setIsBanned(cBanned || pBanned);\n }\n };\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n\n let sub3: { unsubscribe: () => void } | undefined;\n let sub4: { unsubscribe: () => void } | undefined;\n\n if (parentChannel) {\n sub3 = parentChannel.on('member.banned', handleBanned);\n sub4 = parentChannel.on('member.unbanned', handleUnbanned);\n }\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n if (sub3) sub3.unsubscribe();\n if (sub4) sub4.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBanned };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n/**\n * Hook that tracks whether the current user has blocked the other party\n * in a messaging (1-1) channel.\n *\n * Reads the initial value from `channel.state.membership.blocked` and subscribes\n * to `member.blocked` / `member.unblocked` WebSocket events for real-time updates.\n *\n * Only triggers a re-render when the *current user* is the target of the event\n * (i.e., the blocker). When user A blocks user B, only A's membership has\n * `blocked: true`. B is unaffected.\n *\n * This hook is only meaningful for `messaging` channels. For `team` channels,\n * use `useBannedState` instead.\n */\nexport function useBlockedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBlocked, setIsBlocked] = useState<boolean>(() => {\n if (!isDirectChannel(channel)) return false;\n return Boolean(channel?.state?.membership?.blocked);\n });\n\n useEffect(() => {\n if (!channel || !isDirectChannel(channel)) {\n setIsBlocked(false);\n return;\n }\n\n // Sync initial state when channel changes\n setIsBlocked(Boolean(channel.state?.membership?.blocked));\n\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(true);\n }\n };\n\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(false);\n }\n };\n\n const sub1 = channel.on('member.blocked', handleBlocked);\n const sub2 = channel.on('member.unblocked', handleUnblocked);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBlocked };\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isFriendChannel } from '../channelRoleUtils';\n\nexport type OnlineStatus = 'online' | 'offline' | 'unknown';\n\n/**\n * Hook that returns the online/offline status of a specific user.\n *\n * The status is determined by checking `channel.state.watchers` on the\n * \"friend\" channel (direct channel where both members have `owner` role).\n * Real-time updates are received via `user.watching.start` and\n * `user.watching.stop` WebSocket events on that channel.\n *\n * Returns `'unknown'` if the user is not a friend (no qualifying channel found).\n *\n * @param userId – The user ID to check the online status of.\n * @param channels – The full list of loaded channels (from ChannelList).\n */\nexport function useOnlineStatus(\n userId: string | undefined,\n channels: Channel[],\n): OnlineStatus {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Find the friend channel for this user — memoized to avoid re-scans.\n const friendChannel = useMemo(() => {\n if (!userId || !currentUserId || userId === currentUserId) return null;\n return channels.find((ch) => isFriendChannel(ch, userId, currentUserId)) || null;\n }, [channels, userId, currentUserId]);\n\n // Derive initial status from watchers state.\n const [status, setStatus] = useState<OnlineStatus>(() => {\n if (!friendChannel || !userId) return 'unknown';\n return friendChannel.state?.watchers?.[userId] ? 'online' : 'offline';\n });\n\n useEffect(() => {\n if (!friendChannel || !userId) {\n setStatus('unknown');\n return;\n }\n\n // Sync initial state (in case friendChannel ref changed).\n setStatus(friendChannel.state?.watchers?.[userId] ? 'online' : 'offline');\n\n const handleWatchingStart = (event: Event) => {\n if (event.user?.id === userId) {\n setStatus('online');\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n if (event.user?.id === userId) {\n setStatus('offline');\n }\n };\n\n const sub1 = friendChannel.on('user.watching.start', handleWatchingStart);\n const sub2 = friendChannel.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [friendChannel, userId]);\n\n return status;\n}\n","import { useState, useEffect, useMemo, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isFriendChannel } from '../channelRoleUtils';\n\n/**\n * Bulk hook that returns a `Set<string>` of user IDs that are currently online.\n *\n * Only users who are \"friends\" (exist in a direct channel where both\n * members have `owner` role) are tracked. The status is derived from\n * `channel.state.watchers` and kept in sync via `user.watching.start`\n * and `user.watching.stop` WebSocket events at the **client** level\n * for efficiency (single subscription instead of N per-channel ones).\n *\n * Usage in ChannelList: `const onlineUsers = useOnlineUsers(channels);`\n * Then check: `onlineUsers.has(userId)`.\n *\n * @param channels – The full list of loaded channels (from ChannelList).\n */\nexport function useOnlineUsers(channels: Channel[]): Set<string> {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Build a map: friendUserId → Channel (the friend channel).\n // This memoizes the friend channel lookup so we only iterate once per channels change.\n const friendMap = useMemo(() => {\n const map = new Map<string, Channel>();\n if (!currentUserId) return map;\n\n for (const ch of channels) {\n const members = ch.state?.members;\n if (!members) continue;\n\n // Find the \"other\" user in this channel\n for (const memberId of Object.keys(members)) {\n if (memberId === currentUserId) continue;\n if (isFriendChannel(ch, memberId, currentUserId)) {\n map.set(memberId, ch);\n }\n }\n }\n return map;\n }, [channels, currentUserId]);\n\n // Compute the initial set of online users from watchers.\n const computeOnlineSet = (): Set<string> => {\n const set = new Set<string>();\n for (const [userId, ch] of friendMap.entries()) {\n if (ch.state?.watchers?.[userId]) {\n set.add(userId);\n }\n }\n return set;\n };\n\n const [onlineUsers, setOnlineUsers] = useState<Set<string>>(() => computeOnlineSet());\n\n // Keep friendMap in a ref so that event handlers always see the latest version.\n const friendMapRef = useRef(friendMap);\n friendMapRef.current = friendMap;\n\n // Re-compute when friendMap changes (new channels loaded, channels array mutated).\n useEffect(() => {\n setOnlineUsers(computeOnlineSet());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [friendMap]);\n\n // Subscribe at the client level for efficiency.\n useEffect(() => {\n if (!currentUserId) return;\n\n const handleWatchingStart = (event: Event) => {\n const userId = event.user?.id;\n const eventCid = event.cid;\n if (!userId || !eventCid) return;\n\n // Check if this userId belongs to a tracked friend channel\n const tracked = friendMapRef.current.get(userId);\n if (tracked && tracked.cid === eventCid) {\n setOnlineUsers((prev) => {\n if (prev.has(userId)) return prev;\n const next = new Set(prev);\n next.add(userId);\n return next;\n });\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n const userId = event.user?.id;\n const eventCid = event.cid;\n if (!userId || !eventCid) return;\n\n const tracked = friendMapRef.current.get(userId);\n if (tracked && tracked.cid === eventCid) {\n setOnlineUsers((prev) => {\n if (!prev.has(userId)) return prev;\n const next = new Set(prev);\n next.delete(userId);\n return next;\n });\n }\n };\n\n const sub1 = client.on('user.watching.start', handleWatchingStart);\n const sub2 = client.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [client, currentUserId]);\n\n return onlineUsers;\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isPendingMember } from '../channelRoleUtils';\n\n/**\n * Hook that tracks whether the current user is in a 'pending' state for the given channel.\n */\nexport function usePendingState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isPending, setIsPending] = useState<boolean>(() => {\n const membership = channel?.state?.membership || channel?.state?.members?.[currentUserId || ''];\n return isPendingMember(membership?.channel_role as string);\n });\n\n useEffect(() => {\n if (!channel || !currentUserId) {\n setIsPending(false);\n return;\n }\n\n const checkPending = () => {\n const membership = channel.state?.membership || channel.state?.members?.[currentUserId];\n return isPendingMember(membership?.channel_role as string);\n };\n\n // Sync initial state\n setIsPending(checkPending());\n\n const defensiveUpdateState = (event: Record<string, unknown>) => {\n // The SDK does not aggressively mutate local state for all events,\n // so we manually map the incoming `member` data onto the channel state so `checkPending` sees it.\n if (event.member && channel.state && channel.state.membership) {\n channel.state.membership = {\n ...channel.state.membership,\n ...(event.member as Record<string, unknown>),\n } as unknown as Record<string, unknown>;\n }\n };\n\n const handleInviteAction = (event: Record<string, unknown>) => {\n const eventMember = event.member as Record<string, unknown>;\n const eventUser = event.user as Record<string, unknown>;\n const eventUserId = eventMember?.user_id || (eventMember?.user as Record<string, unknown>)?.id || eventUser?.id;\n if (eventUserId !== currentUserId) return; // Only react to own invite events\n\n const eventCid =\n event.cid ||\n (event.channel as Record<string, unknown>)?.cid ||\n (event.channel_id ? `${event.channel_type}:${event.channel_id}` : undefined);\n if (eventCid === channel.cid) {\n defensiveUpdateState(event);\n setIsPending(checkPending());\n }\n };\n\n const client = channel.getClient();\n const sub1 = client.on('notification.invite_accepted', handleInviteAction);\n const sub2 = client.on('notification.invite_rejected', handleInviteAction);\n const sub3 = client.on('notification.invite_messaging_skipped', handleInviteAction);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isPending };\n}\n","import React, { useEffect, useState, useCallback, useMemo } from 'react';\nimport { VList } from 'virtua';\nimport type { Channel, Event, ChannelFilters } from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChannelListUpdates } from '../hooks/useChannelListUpdates';\nimport { useOnlineUsers } from '../hooks/useOnlineUsers';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { useChannelRowUpdates } from '../hooks/useChannelRowUpdates';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelItemProps, ChannelListProps } from '../types';\n\nexport type { ChannelListProps, ChannelItemProps } from '../types';\nimport type { ChannelActionsProps } from '../types';\nimport { TopicModal } from './TopicModal';\nimport { DefaultChannelActions, computeDefaultActions } from './ChannelActions';\nimport { isDirectChannel, hasTopicsEnabled } from '../channelTypeUtils';\nimport { canManageChannel, isPendingMember, isSkippedMember, isFriendChannel } from '../channelRoleUtils';\n\nexport { DefaultChannelActions } from './ChannelActions';\nexport type { ChannelAction, ChannelActionsProps } from '../types';\n\n/**\n * Get a human-readable preview string for the last message,\n * handling regular, system, and signal message types.\n */\nfunction getLastMessagePreview(\n channel: Channel,\n myUserId?: string,\n): { text: string; user: string; timestamp?: string | Date } {\n const lastMsg = channel.state?.latestMessages?.slice(-1)[0];\n if (!lastMsg) return { text: '', user: '' };\n\n const timestamp = lastMsg.created_at;\n\n const msgType = lastMsg.type || 'regular';\n const rawText = lastMsg.text ?? '';\n\n if (msgType === 'system') {\n const userMap = buildUserMap(channel.state);\n return { text: parseSystemMessage(rawText, userMap), user: '', timestamp };\n }\n\n if (msgType === 'signal') {\n const result = parseSignalMessage(rawText, myUserId || '');\n return { text: result?.text || rawText, user: '', timestamp };\n }\n\n // Display 'Sticker' if message is a sticker\n if (msgType === 'sticker' || (lastMsg as Record<string, unknown>).sticker_url) {\n return { text: 'Sticker', user: lastMsg.user?.name || lastMsg.user_id || '', timestamp };\n }\n\n // Regular / other\n let displayText = rawText;\n if (!displayText && lastMsg.attachments && lastMsg.attachments.length > 0) {\n const att = lastMsg.attachments[0];\n const type = att.type || '';\n switch (type) {\n case 'image':\n displayText = '📷 Photo';\n break;\n case 'video':\n displayText = '🎬 Video';\n break;\n case 'voiceRecording':\n displayText = '🎤 Voice message';\n break;\n default:\n displayText = '📎 File';\n break;\n }\n if (lastMsg.attachments.length > 1) {\n displayText += ` +${lastMsg.attachments.length - 1}`;\n }\n }\n\n // Format mentions if necessary\n const lastMsgRecord = lastMsg as Record<string, unknown>;\n const mentionedUsers = lastMsgRecord.mentioned_users as string[] | undefined;\n const mentionedAll = lastMsgRecord.mentioned_all as boolean | undefined;\n\n if (displayText && (mentionedAll || (mentionedUsers && mentionedUsers.length > 0))) {\n const userMap = buildUserMap(channel.state);\n displayText = replaceMentionsForPreview(displayText, lastMsg as any, userMap);\n }\n\n return {\n text: displayText,\n user: lastMsg.user?.name || lastMsg.user_id || '',\n timestamp,\n };\n}\n\n/* ----------------------------------------------------------\n Memoized channel list item (exported for consumer reuse)\n ---------------------------------------------------------- */\nexport const ChannelItem: React.FC<ChannelItemProps> = React.memo(({\n channel,\n isActive,\n hasUnread,\n unreadCount,\n lastMessageText,\n lastMessageUser,\n lastMessageTimestamp,\n onSelect,\n AvatarComponent,\n isBlocked,\n isPending,\n pendingBadgeLabel,\n blockedBadgeLabel,\n isClosedTopic,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n isOnline,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Subscribe to channel.updated so that when name/image/description change,\n // we re-render from within (bypasses React.memo which only blocks parent-driven re-renders)\n const [updateCount, forceUpdate] = useState(0);\n useEffect(() => {\n const handleUpdate = () => forceUpdate((c) => c + 1);\n const sub1 = channel.on('channel.updated', handleUpdate);\n const sub2 = channel.on('channel.pinned', handleUpdate);\n const sub3 = channel.on('channel.unpinned', handleUpdate);\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n };\n }, [channel]);\n\n const defaultActions = useMemo(\n () => computeDefaultActions(channel, currentUserId, { onAddTopic, onEditTopic, onToggleCloseTopic, isBlocked, actionLabels, actionIcons }),\n [channel, currentUserId, updateCount, onAddTopic, onEditTopic, onToggleCloseTopic, isBlocked, actionLabels, actionIcons],\n );\n\n const filteredActions = useMemo(() => {\n if (!hiddenActions || hiddenActions.length === 0) return defaultActions;\n return defaultActions.filter(a => !hiddenActions.includes(a.id));\n }, [defaultActions, hiddenActions]);\n const ActionsComponent = ChannelActionsComponent || DefaultChannelActions;\n\n const name = channel.data?.name || channel.cid;\n const image = channel.data?.image as string | undefined;\n const showUnread = hasUnread && !isActive;\n\n const timestampText = useMemo(() => {\n if (!lastMessageTimestamp) return null;\n const d = new Date(lastMessageTimestamp);\n if (isNaN(d.getTime())) return null;\n const today = new Date();\n const isToday = d.toDateString() === today.toDateString();\n return isToday\n ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n : d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }, [lastMessageTimestamp]);\n\n const handleClick = useCallback(() => {\n onSelect(channel);\n }, [channel, onSelect]);\n\n const itemClass = [\n 'ermis-channel-list__item',\n isActive ? 'ermis-channel-list__item--active' : '',\n showUnread ? 'ermis-channel-list__item--unread' : '',\n isPending ? 'ermis-channel-list__item--pending' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} onClick={handleClick}>\n <div className=\"ermis-channel-list__item-avatar-wrapper\">\n <AvatarComponent image={image} name={name} size={40} disableLightbox />\n {isOnline !== undefined && (\n <span className={`ermis-channel-list__online-dot ermis-channel-list__online-dot--${isOnline ? 'online' : 'offline'}`} />\n )}\n </div>\n <div className=\"ermis-channel-list__item-content\">\n <div className=\"ermis-channel-list__item-top-row\">\n <div className=\"ermis-channel-list__item-name\">{name}</div>\n {channel.data?.is_pinned === true && !isClosedTopic && PinnedIconComponent && (\n <span className=\"ermis-channel-list__pinned-icon\" title=\"Pinned\">\n <PinnedIconComponent />\n </span>\n )}\n {isClosedTopic && (\n <span className=\"ermis-channel-list__closed-icon\">\n {closedTopicIcon || (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n </span>\n )}\n {!isClosedTopic && timestampText && <div className=\"ermis-channel-list__item-timestamp\">{timestampText}</div>}\n\n {isPending && (\n <span className=\"ermis-channel-list__pending-badge\">{pendingBadgeLabel || 'Invited'}</span>\n )}\n\n {isBlocked && (\n <span className=\"ermis-channel-list__blocked-icon\" title={blockedBadgeLabel || \"Blocked\"}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </span>\n )}\n </div>\n <div className=\"ermis-channel-list__item-bottom-row\">\n {!isClosedTopic && lastMessageText && (\n <div className=\"ermis-channel-list__item-last-message\">\n {lastMessageUser && (\n <span className=\"ermis-channel-list__item-last-message-user\">\n {lastMessageUser}:{' '}\n </span>\n )}\n <span>{lastMessageText}</span>\n </div>\n )}\n\n {!isClosedTopic && (\n <div className=\"ermis-channel-list__item-badges\">\n {showUnread && unreadCount > 0 && (\n <span className=\"ermis-channel-list__unread-badge\">\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n {!isPending && (\n <div className=\"ermis-channel-list__item-actions-wrapper\">\n <ActionsComponent channel={channel} actions={filteredActions} onClose={() => { }} />\n </div>\n )}\n </div>\n );\n});\nChannelItem.displayName = 'ChannelItem';\n\nexport const DefaultPinnedIcon = React.memo(() => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n));\nDefaultPinnedIcon.displayName = 'DefaultPinnedIcon';\n\nconst DefaultLoading = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__loading\">{text || 'Loading channels...'}</div>\n));\nDefaultLoading.displayName = 'DefaultLoading';\n\nconst DefaultEmpty = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__empty\">{text || 'No channels found'}</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/* ----------------------------------------------------------\n Virtual Row Component to map channel and defer parsing\n ---------------------------------------------------------- */\ntype ChannelRowProps = {\n channel: Channel;\n isActive: boolean;\n handleSelect: (c: Channel) => void;\n renderChannel?: (c: Channel, active: boolean) => React.ReactNode;\n ChannelItemComponent: React.ComponentType<ChannelItemProps>;\n AvatarComponent: React.ComponentType<any>;\n currentUserId?: string;\n pendingBadgeLabel?: string;\n blockedBadgeLabel?: string;\n closedTopicIcon?: React.ReactNode;\n PinnedIconComponent?: React.ComponentType;\n ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;\n onAddTopic?: (channel: Channel) => void;\n onEditTopic?: (channel: Channel) => void;\n onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;\n hiddenActions?: string[];\n actionLabels?: import('../types').ChannelActionLabels;\n actionIcons?: import('../types').ChannelActionIcons;\n isOnline?: boolean;\n};\n\nconst ChannelRow: React.FC<ChannelRowProps> = React.memo(({\n channel,\n isActive,\n handleSelect,\n renderChannel,\n ChannelItemComponent,\n AvatarComponent,\n currentUserId,\n pendingBadgeLabel,\n blockedBadgeLabel,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n isOnline,\n}) => {\n // Use the new custom hook to handle all row-level realtime updates\n const { isBannedInChannel, isBlockedInChannel, updateCount } = useChannelRowUpdates(channel, currentUserId);\n const { isPending } = usePendingState(channel, currentUserId);\n const isSkipped = isSkippedMember(channel.state?.membership?.channel_role as string);\n\n const channelState = channel.state as unknown as Record<string, unknown> | undefined;\n const rawUnreadCount = (channelState?.unreadCount as number) ?? 0;\n\n const isClosedTopic = channel.data?.is_closed_topic === true;\n\n // Render logic continues...\n const unreadCount = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? 0 : rawUnreadCount;\n const hasUnread = unreadCount > 0;\n\n // Derive last message preview computation\n const { text: rawLastMessageText, user: rawLastMessageUser, timestamp: rawLastMessageTimestamp } = useMemo(\n () => getLastMessagePreview(channel, currentUserId),\n // Recompute if latestMessage changes or we get a force update\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [channel, channel.state?.latestMessages, updateCount]\n );\n\n // Hide last message preview when banned, blocked, pending or skipped\n const lastMessageText = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? '' : rawLastMessageText;\n const lastMessageUser = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? '' : rawLastMessageUser;\n const lastMessageTimestamp = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? null : rawLastMessageTimestamp;\n\n if (renderChannel) {\n return (\n <div onClick={() => handleSelect(channel)}>\n {renderChannel(channel, isActive)}\n </div>\n );\n }\n\n return (\n <ChannelItemComponent\n channel={channel}\n isActive={isActive}\n hasUnread={hasUnread}\n unreadCount={unreadCount}\n lastMessageText={lastMessageText}\n lastMessageUser={lastMessageUser}\n lastMessageTimestamp={lastMessageTimestamp}\n onSelect={handleSelect}\n AvatarComponent={AvatarComponent}\n isBlocked={isBlockedInChannel}\n isPending={isPending}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n isClosedTopic={isClosedTopic}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={onAddTopic}\n onEditTopic={onEditTopic}\n onToggleCloseTopic={onToggleCloseTopic}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={isOnline}\n />\n );\n});\nChannelRow.displayName = 'ChannelRow';\n\nexport const ChannelTopicGroup = React.memo(({\n channel,\n activeChannel,\n handleSelect,\n renderChannel,\n ChannelItemComponent,\n AvatarComponent,\n GeneralTopicAvatarComponent,\n TopicAvatarComponent,\n currentUserId,\n pendingBadgeLabel,\n blockedBadgeLabel,\n generalTopicLabel,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n}: any) => {\n const { updateCount } = useChannelRowUpdates(channel, currentUserId);\n const [isExpanded, setIsExpanded] = useState(true);\n const [topicUpdateCount, setTopicUpdateCount] = useState(0);\n\n useEffect(() => {\n const subs: { unsubscribe: () => void }[] = [];\n const handleUpdate = () => setTopicUpdateCount((c) => c + 1);\n const currentTopics = channel.state?.topics || [];\n currentTopics.forEach((t: Channel) => {\n subs.push(t.on('channel.pinned', handleUpdate));\n subs.push(t.on('channel.unpinned', handleUpdate));\n subs.push(t.on('message.new', handleUpdate));\n subs.push(t.on('message.deleted', handleUpdate));\n });\n return () => {\n subs.forEach((s) => s.unsubscribe());\n };\n }, [channel.state?.topics]);\n\n const handleToggle = useCallback(() => setIsExpanded((prev) => !prev), []);\n\n const userRole = channel.state?.members?.[currentUserId]?.channel_role;\n const hasTopicAddPermission = canManageChannel(userRole);\n\n const getTopicTime = (t: Channel) => {\n const lastMsg = t.state?.latestMessages?.slice(-1)[0];\n if (lastMsg?.created_at) return new Date(lastMsg.created_at).getTime();\n if (t.data?.last_message_at) return new Date(t.data.last_message_at as string | Date).getTime();\n if (t.data?.created_at) return new Date(t.data.created_at as string | Date).getTime();\n return 0;\n };\n\n const topics = useMemo(() => {\n const allTopics = channel.state?.topics || [];\n return [...allTopics].sort((a: any, b: any) => {\n const aPinned = a.data?.is_pinned === true;\n const bPinned = b.data?.is_pinned === true;\n if (aPinned && !bPinned) return -1;\n if (!aPinned && bPinned) return 1;\n\n return getTopicTime(b) - getTopicTime(a);\n });\n }, [channel.state?.topics, topicUpdateCount]);\n const name = channel.data?.name || channel.cid;\n const image = channel.data?.image as string | undefined;\n\n const GeneralAvatar = useCallback(() => (\n <div className=\"ermis-channel-list__topic-hashtag\">#</div>\n ), []);\n\n const TopicEmojiAvatar = useCallback(({ image }: any) => {\n let emoji = '💬';\n if (image && typeof image === 'string' && image.startsWith('emoji://')) {\n emoji = image.replace('emoji://', '');\n }\n return <div className=\"ermis-channel-list__topic-hashtag\">{emoji}</div>;\n }, []);\n\n const generalChannelProxy = useMemo(() => {\n return new Proxy(channel, {\n get(target, prop, receiver) {\n if (prop === 'data') {\n return { ...target.data, name: generalTopicLabel || 'general', is_pinned: false };\n }\n const value = Reflect.get(target, prop, receiver);\n return typeof value === 'function' ? value.bind(target) : value;\n }\n });\n }, [channel, generalTopicLabel]);\n\n const defaultActions = useMemo(\n () => computeDefaultActions(channel, currentUserId, { onAddTopic, actionLabels, actionIcons }),\n [channel, currentUserId, updateCount, onAddTopic, actionLabels, actionIcons],\n );\n\n const filteredActions = useMemo(() => {\n if (!hiddenActions || hiddenActions.length === 0) return defaultActions;\n return defaultActions.filter((a: any) => !hiddenActions.includes(a.id));\n }, [defaultActions, hiddenActions]);\n const ActionsComponent = ChannelActionsComponent || DefaultChannelActions;\n\n return (\n <div className=\"ermis-channel-list__topic-group\">\n <div\n className={`ermis-channel-list__topic-header ${isExpanded ? 'ermis-channel-list__topic-header--expanded' : ''}`}\n onClick={handleToggle}\n >\n <AvatarComponent image={image} name={name} size={40} disableLightbox />\n <div className=\"ermis-channel-list__topic-header-name\">{name}</div>\n\n {channel.data?.is_pinned === true && PinnedIconComponent && (\n <span className=\"ermis-channel-list__pinned-icon\" title=\"Pinned\">\n <PinnedIconComponent />\n </span>\n )}\n\n <div className=\"ermis-channel-list__topic-actions-wrapper\">\n <ActionsComponent channel={channel} actions={filteredActions} onClose={() => { }} />\n </div>\n\n <svg\n className=\"ermis-channel-list__accordion-icon\"\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n\n {isExpanded && (\n <div className=\"ermis-channel-list__topic-sublist\">\n <ChannelRow\n channel={generalChannelProxy as any}\n isActive={activeChannel?.cid === channel.cid}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={GeneralTopicAvatarComponent || GeneralAvatar}\n currentUserId={currentUserId}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={() => null}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n />\n {topics.map((topicChannel: any) => (\n <ChannelRow\n key={topicChannel.cid}\n channel={topicChannel}\n isActive={activeChannel?.cid === topicChannel.cid}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={TopicAvatarComponent || TopicEmojiAvatar}\n currentUserId={currentUserId}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onEditTopic={onEditTopic}\n onToggleCloseTopic={onToggleCloseTopic}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\nChannelTopicGroup.displayName = 'ChannelTopicGroup';\n\nexport const ChannelList: React.FC<ChannelListProps> = React.memo(({\n filters = { type: ['messaging', 'team', 'meeting'], include_pinned_messages: true } as unknown as ChannelFilters,\n sort = [],\n options = { message_limit: 25 } as unknown as ChannelListProps['options'],\n renderChannel,\n onChannelSelect,\n className,\n LoadingIndicator = DefaultLoading,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n ChannelItemComponent = ChannelItem,\n pendingInvitesLabel,\n channelsLabel = 'Channels',\n pendingBadgeLabel,\n loadingLabel,\n emptyStateLabel = 'No channels found',\n blockedBadgeLabel = 'Blocked',\n ChannelTopicGroupComponent,\n GeneralTopicAvatarComponent,\n TopicAvatarComponent,\n generalTopicLabel = 'general',\n onAddTopic,\n TopicEmojiPickerComponent,\n closedTopicIcon,\n PinnedIconComponent = DefaultPinnedIcon,\n ChannelActionsComponent,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n showOnlineStatus = true,\n}) => {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n const [channels, setChannels] = useState<Channel[]>([]);\n const [loading, setLoading] = useState(true);\n const [isPendingExpanded, setIsPendingExpanded] = useState(true);\n const [addingTopicForChannel, setAddingTopicForChannel] = useState<Channel | null>(null);\n const [editingTopicForChannel, setEditingTopicForChannel] = useState<Channel | null>(null);\n\n const handleAddTopicClick = useCallback((channel: Channel) => {\n if (onAddTopic) {\n onAddTopic(channel);\n } else {\n setAddingTopicForChannel(channel);\n }\n }, [onAddTopic]);\n\n const handleEditTopicClick = useCallback((channel: Channel) => {\n if (onEditTopic) {\n onEditTopic(channel);\n } else {\n setEditingTopicForChannel(channel);\n }\n }, [onEditTopic]);\n\n const handleToggleCloseTopicClick = useCallback(async (channel: Channel, isClosed: boolean) => {\n if (onToggleCloseTopic) {\n onToggleCloseTopic(channel, isClosed);\n return;\n }\n\n const parentCid = channel.data?.parent_cid as string | undefined;\n if (!parentCid) return;\n\n const parentChannel = client.activeChannels[parentCid];\n if (!parentChannel) return;\n\n try {\n if (isClosed) {\n await parentChannel.reopenTopic(channel.cid);\n } else {\n await parentChannel.closeTopic(channel.cid);\n }\n } catch (err) {\n console.error('Failed to toggle topic close state', err);\n }\n }, [client.activeChannels, onToggleCloseTopic]);\n\n // Group channels into pending and regular\n const { pendingChannels, regularChannels } = useMemo<{ pendingChannels: Channel[], regularChannels: Channel[] }>(() => {\n const pending: Channel[] = [];\n const pinned: Channel[] = [];\n const regular: Channel[] = [];\n\n channels.forEach(ch => {\n const ms = ch.state?.membership as Record<string, unknown> | undefined;\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n \n if (isSkipped) {\n return; // Filter out completely\n }\n\n if (isPending) {\n pending.push(ch);\n } else if (ch.data?.is_pinned) {\n pinned.push(ch);\n } else {\n regular.push(ch);\n }\n });\n\n return { pendingChannels: pending, regularChannels: [...pinned, ...regular] };\n }, [channels]);\n\n const filtersKey = useMemo(() => JSON.stringify(filters), [filters]);\n\n const loadChannels = useCallback(async () => {\n try {\n setLoading(true);\n const result = await client.queryChannels(filters, sort, options as { message_limit?: number });\n setChannels(result);\n } catch (err) {\n console.error('Failed to load channels:', err);\n } finally {\n setLoading(false);\n }\n }, [client, filtersKey]);\n\n useEffect(() => {\n loadChannels();\n }, [loadChannels]);\n\n // Real-time: List manipulation (move to top, add, delete)\n useChannelListUpdates(channels, setChannels);\n\n // Online status: compute set of online friend user IDs (skip if disabled)\n const onlineUsers = useOnlineUsers(showOnlineStatus ? channels : []);\n\n // Helper: get the \"other\" user ID from a direct channel\n const getOtherUserId = useCallback((channel: Channel): string | undefined => {\n if (!isDirectChannel(channel) || !client.userID) return undefined;\n const members = channel.state?.members;\n if (!members) return undefined;\n for (const memberId of Object.keys(members)) {\n if (memberId !== client.userID) return memberId;\n }\n return undefined;\n }, [client.userID]);\n\n // Helper: compute isOnline for a channel (undefined for non-friend channels)\n const getIsOnline = useCallback((channel: Channel): boolean | undefined => {\n const otherUserId = getOtherUserId(channel);\n if (!otherUserId || !client.userID) return undefined;\n if (!isFriendChannel(channel, otherUserId, client.userID)) return undefined;\n return onlineUsers.has(otherUserId);\n }, [getOtherUserId, onlineUsers, client.userID]);\n\n const handleSelect = useCallback(\n (channel: Channel) => {\n setActiveChannel(channel);\n onChannelSelect?.(channel);\n\n // Mark as read when user selects a channel (skip if banned, blocked, or pending)\n const ms = channel.state?.membership as Record<string, unknown> | undefined;\n const chState = channel.state as unknown as Record<string, unknown> | undefined;\n const isBannedInChannel = Boolean(ms?.banned);\n const isBlockedInChannel = isDirectChannel(channel) && Boolean(ms?.blocked);\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n\n if (!isBannedInChannel && !isBlockedInChannel && !isPending && !isSkipped && (chState?.unreadCount as number) > 0) {\n channel.markRead().catch(() => { });\n // Optimistically reset unread to update UI immediately\n if (chState) chState.unreadCount = 0;\n setChannels((prev) => [...prev]);\n }\n },\n [setActiveChannel, onChannelSelect, setChannels],\n );\n\n if (loading) return <LoadingIndicator text={loadingLabel} />;\n if (channels.length === 0) return <EmptyStateIndicator text={emptyStateLabel} />;\n\n return (\n <div className={`ermis-channel-list${className ? ` ${className}` : ''}`}>\n {/* VList requires its container to have a height to work. */}\n <VList style={{ height: '100%' }}>\n {pendingChannels.length > 0 && (\n <div\n className=\"ermis-channel-list__accordion-header\"\n onClick={() => setIsPendingExpanded(prev => !prev)}\n >\n <span>\n {typeof pendingInvitesLabel === 'function'\n ? pendingInvitesLabel(pendingChannels.length)\n : pendingInvitesLabel || `Invites (${pendingChannels.length})`}\n </span>\n <svg\n className={`ermis-channel-list__accordion-icon ${isPendingExpanded ? 'ermis-channel-list__accordion-icon--expanded' : ''}`}\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n )}\n {isPendingExpanded && pendingChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={getIsOnline(channel)}\n />\n );\n })}\n {pendingChannels.length > 0 && regularChannels.length > 0 && (\n <div className=\"ermis-channel-list__accordion-header ermis-channel-list__accordion-header--static\">\n <span>{channelsLabel}</span>\n </div>\n )}\n {regularChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n const isTeamWithTopics = hasTopicsEnabled(channel);\n\n if (isTeamWithTopics) {\n const GroupComponent = ChannelTopicGroupComponent || ChannelTopicGroup;\n return (\n <GroupComponent\n key={channel.cid}\n channel={channel}\n activeChannel={activeChannel}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n GeneralTopicAvatarComponent={GeneralTopicAvatarComponent}\n TopicAvatarComponent={TopicAvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n generalTopicLabel={generalTopicLabel}\n onAddTopic={handleAddTopicClick}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onEditTopic={handleEditTopicClick}\n onToggleCloseTopic={handleToggleCloseTopicClick}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n />\n );\n }\n\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={handleAddTopicClick}\n onEditTopic={handleEditTopicClick}\n onToggleCloseTopic={handleToggleCloseTopicClick}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={getIsOnline(channel)}\n />\n );\n })}\n </VList>\n {addingTopicForChannel && (\n <TopicModal\n isOpen={true}\n onClose={() => setAddingTopicForChannel(null)}\n parentChannel={addingTopicForChannel}\n EmojiPickerComponent={TopicEmojiPickerComponent}\n />\n )}\n {editingTopicForChannel && (\n <TopicModal\n isOpen={true}\n onClose={() => setEditingTopicForChannel(null)}\n topic={editingTopicForChannel}\n EmojiPickerComponent={TopicEmojiPickerComponent}\n />\n )}\n </div>\n );\n});\n\nChannelList.displayName = 'ChannelList'; 'ChannelList';\n","import React, { useState, useCallback } from 'react';\nimport type { CreateTopicData, EditTopicData } from '@ermis-network/ermis-chat-sdk';\nimport { Modal } from './Modal';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { TopicModalProps } from '../types';\n\nconst DEFAULT_TOPIC_ICONS = ['💬', '🔥', '🚀', '⭐', '💡', '🎉', '📌', '📁', '🎨', '💻', '📈', '🤝'];\n\nexport const TopicModal: React.FC<TopicModalProps> = React.memo(({\n isOpen,\n onClose,\n onSuccess,\n EmojiPickerComponent,\n parentChannel,\n topic,\n title = topic ? 'Edit Topic' : 'Create Topic',\n nameLabel = 'Topic Name',\n namePlaceholder = 'Enter topic name',\n emojiLabel = 'Topic icon',\n descriptionLabel = 'Description',\n descriptionPlaceholder = 'Enter topic description',\n cancelButtonLabel = 'Cancel',\n saveButtonLabel = topic ? 'Save' : 'Create',\n savingButtonLabel = topic ? 'Saving...' : 'Creating...',\n}) => {\n const { activeChannel, client } = useChatClient();\n \n const originalName = (topic?.data?.name as string) || '';\n const originalImage = (topic?.data?.image as string) || '';\n const originalEmoji = originalImage.startsWith('emoji://') ? originalImage.replace('emoji://', '') : '';\n const originalDescription = (topic?.data?.description as string) || '';\n\n const [name, setName] = useState(originalName);\n const [emoji, setEmoji] = useState(originalEmoji);\n const [description, setDescription] = useState(originalDescription);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const targetParent = parentChannel || activeChannel;\n\n const handleSave = useCallback(async () => {\n if (!name.trim() || !emoji) return;\n\n // Resolve parent channel (owner of topics)\n let editorParent = targetParent;\n if (topic && topic.data?.parent_cid) {\n editorParent = client.activeChannels[topic.data.parent_cid as string] || editorParent;\n }\n \n if (!editorParent && !topic) return;\n\n setIsSaving(true);\n setError(null);\n\n try {\n if (topic) {\n if (!editorParent) throw new Error(\"Parent channel not found\");\n \n const payload: EditTopicData = {};\n if (name.trim() !== originalName) payload.name = name.trim();\n if (emoji !== originalEmoji) payload.image = emoji ? `emoji://${emoji}` : '';\n if (description.trim() !== originalDescription) payload.description = description.trim();\n\n if (Object.keys(payload).length > 0 && topic.cid) {\n await editorParent.editTopic(topic.cid, payload);\n }\n\n if (onSuccess) {\n onSuccess(topic);\n } else {\n onClose();\n }\n } else {\n if (!editorParent) return;\n const payload: CreateTopicData = {\n name: name.trim(),\n };\n\n if (emoji) {\n payload.image = `emoji://${emoji}`;\n }\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n await editorParent.createTopic(payload);\n\n if (onSuccess) {\n onSuccess(editorParent);\n } else {\n onClose();\n setName('');\n setEmoji('');\n setDescription('');\n }\n }\n } catch (err: any) {\n setError(err?.message || (topic ? 'Failed to save topic' : 'Failed to create topic'));\n } finally {\n setIsSaving(false);\n }\n }, [targetParent, topic, name, emoji, description, originalName, originalEmoji, originalDescription, onSuccess, onClose, client.activeChannels]);\n\n const isValid = name.trim().length > 0 && emoji.length > 0;\n\n const footer = (\n <div className=\"ermis-create-topic__footer\">\n <button className=\"ermis-create-topic__btn ermis-create-topic__btn--cancel\" onClick={onClose} disabled={isSaving}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-topic__btn ermis-create-topic__btn--create\" onClick={handleSave} disabled={isSaving || !isValid}>\n {isSaving ? savingButtonLabel : saveButtonLabel}\n </button>\n </div>\n );\n\n return (\n <Modal isOpen={isOpen} onClose={isSaving ? () => { } : onClose} title={title} maxWidth=\"400px\" footer={footer}>\n <div className=\"ermis-create-topic__body\">\n <div className=\"ermis-create-topic__live-preview\">\n <span className=\"ermis-create-topic__live-preview-emoji\">{emoji || <span style={{opacity: 0.3}}>#</span>}</span>\n <span className=\"ermis-create-topic__live-preview-name\">{name || namePlaceholder}</span>\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{nameLabel} <span className=\"ermis-create-topic__required\">*</span></label>\n <input\n className=\"ermis-create-topic__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n autoFocus\n />\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{emojiLabel} <span className=\"ermis-create-topic__required\">*</span></label>\n\n <div className=\"ermis-create-topic__emoji-picker\">\n {EmojiPickerComponent ? (\n <EmojiPickerComponent onSelect={(e: any) => setEmoji(e.native || e.emoji || e.id || e)} />\n ) : (\n <div className=\"ermis-create-topic__default-icons\">\n {DEFAULT_TOPIC_ICONS.map(icon => (\n <button\n key={icon}\n type=\"button\"\n className={`ermis-create-topic__default-icon ${icon === emoji ? 'ermis-create-topic__default-icon--active' : ''}`}\n onClick={() => setEmoji(icon)}\n disabled={isSaving}\n >\n {icon}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-create-topic__input\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n style={{ resize: 'vertical' }}\n />\n </div>\n\n {error && (\n <div className=\"ermis-create-topic__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nTopicModal.displayName = 'TopicModal';\n","import React, { useState, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { ChannelAction, ChannelActionLabels, ChannelActionIcons, ChannelActionsProps } from '../types';\nimport { Dropdown } from './Dropdown';\nimport { isDirectChannel, isGroupChannel, isTopicChannel } from '../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../channelRoleUtils';\n\n/* ----------------------------------------------------------\n SVG Icons for default actions\n ---------------------------------------------------------- */\nconst PinIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /></svg>);\nconst UnpinIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /><line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\" /></svg>);\nconst BlockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" /></svg>);\nconst LeaveIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" /><polyline points=\"16 17 21 12 16 7\" /><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" /></svg>);\nconst TrashIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"3 6 5 6 21 6\" /><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" /></svg>);\nconst LockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 10 0v4\" /></svg>);\nconst UnlockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 9.9-1\" /></svg>);\nconst CreateTopicIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>);\nconst EditIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" /><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" /></svg>);\nconst MoreIcon = () => (<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"1\" /><circle cx=\"19\" cy=\"12\" r=\"1\" /><circle cx=\"5\" cy=\"12\" r=\"1\" /></svg>);\n\n/* ----------------------------------------------------------\n computeDefaultActions\n Derives a list of ChannelAction[] based on channel type\n and the current user's role. Currently actions only log\n to console — real API calls will be wired later.\n ---------------------------------------------------------- */\nexport function computeDefaultActions(\n channel: Channel,\n currentUserId?: string,\n options?: {\n onAddTopic?: (channel: Channel) => void;\n onEditTopic?: (channel: Channel) => void;\n onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;\n isBlocked?: boolean;\n actionLabels?: ChannelActionLabels;\n actionIcons?: ChannelActionIcons;\n },\n): ChannelAction[] {\n const actions: ChannelAction[] = [];\n if (!currentUserId) return actions;\n\n const isDirect = isDirectChannel(channel);\n const isTeamOrMeeting = isGroupChannel(channel);\n const isTopic = isTopicChannel(channel);\n const isClosed = channel.data?.is_closed_topic === true;\n\n const ms = channel.state?.members?.[currentUserId] || channel.state?.membership;\n const role = ms?.channel_role;\n const isBlocked = options?.isBlocked !== undefined ? options.isBlocked : (ms as any)?.blocked;\n const isPinned = channel.data?.is_pinned === true;\n\n // Pin / Unpin — available for all channel types\n const actionLabels = options?.actionLabels;\n\n const pinLabel = isPinned\n ? (isTopic ? (actionLabels?.unpinTopic || 'Unpin topic') : (actionLabels?.unpinChannel || 'Unpin channel'))\n : (isTopic ? (actionLabels?.pinTopic || 'Pin topic') : (actionLabels?.pinChannel || 'Pin channel'));\n\n const actionIcons = options?.actionIcons;\n\n const pinIcon = isPinned\n ? (actionIcons?.UnpinIcon || <UnpinIcon />)\n : (actionIcons?.PinIcon || <PinIcon />);\n\n actions.push({\n id: isPinned ? 'unpin' : 'pin',\n label: pinLabel,\n icon: pinIcon,\n onClick: async (ch) => {\n try {\n if (isPinned) {\n await ch.unpin();\n } else {\n await ch.pin();\n }\n } catch (e) {\n console.error('Error toggling pin state', e);\n }\n },\n });\n\n if (isDirect) {\n // Direct channel: Block / Unblock\n actions.push({\n id: isBlocked ? 'unblock' : 'block',\n label: isBlocked ? (actionLabels?.unblockUser || 'Unblock user') : (actionLabels?.blockUser || 'Block user'),\n icon: isBlocked ? (actionIcons?.UnblockIcon || <BlockIcon />) : (actionIcons?.BlockIcon || <BlockIcon />),\n isDanger: !isBlocked,\n onClick: async (ch) => {\n try {\n if (isBlocked) {\n await ch.unblockUser();\n } else {\n await ch.blockUser();\n }\n } catch (e) {\n console.error('Error toggling block state', e);\n }\n },\n });\n } else if (isTopic) {\n // Topic: Edit topic (owner & moder only)\n if (canManageChannel(role)) {\n actions.push({\n id: 'edit_topic',\n label: actionLabels?.editTopic || 'Edit topic',\n icon: actionIcons?.EditTopicIcon || <EditIcon />,\n onClick: (ch) => {\n options?.onEditTopic?.(ch);\n },\n });\n }\n // Topic: Close / Reopen (owner & moder only)\n if (canManageChannel(role)) {\n actions.push({\n id: isClosed ? 'reopen' : 'close',\n label: isClosed ? (actionLabels?.reopenTopic || 'Reopen topic') : (actionLabels?.closeTopic || 'Close topic'),\n icon: isClosed ? (actionIcons?.ReopenTopicIcon || <UnlockIcon />) : (actionIcons?.CloseTopicIcon || <LockIcon />),\n isDanger: !isClosed,\n onClick: (ch) => {\n options?.onToggleCloseTopic?.(ch, isClosed);\n },\n });\n }\n } else if (isTeamOrMeeting) {\n // Team channel: Create Topic (owner & moder, only if topics enabled)\n const hasTopicsEnabled = Boolean(channel.data?.topics_enabled);\n if (hasTopicsEnabled && canManageChannel(role) && options?.onAddTopic) {\n actions.push({\n id: 'create_topic',\n label: actionLabels?.createTopic || 'Create topic',\n icon: actionIcons?.CreateTopicIcon || <CreateTopicIcon />,\n onClick: (ch) => { options.onAddTopic!(ch); },\n });\n }\n if (role === CHANNEL_ROLES.OWNER) {\n actions.push({\n id: 'delete',\n label: actionLabels?.deleteChannel || 'Delete channel',\n icon: actionIcons?.DeleteChannelIcon || <TrashIcon />,\n isDanger: true,\n onClick: async (ch) => {\n try {\n await ch.delete();\n } catch (e) {\n console.error('Error deleting channel', e);\n }\n },\n });\n }\n if (role === CHANNEL_ROLES.MODERATOR || role === CHANNEL_ROLES.MEMBER) {\n actions.push({\n id: 'leave',\n label: actionLabels?.leaveChannel || 'Leave channel',\n icon: actionIcons?.LeaveChannelIcon || <LeaveIcon />,\n isDanger: true,\n onClick: async (ch) => {\n try {\n await ch.removeMembers([currentUserId]);\n } catch (e) {\n console.error('Error leaving channel', e);\n }\n },\n });\n }\n }\n\n return actions;\n}\n\n/* ----------------------------------------------------------\n DefaultChannelActions\n The default UI component that renders the \"more\" trigger\n button and the dropdown menu. Consumer can fully replace\n this via ChannelActionsComponent prop.\n ---------------------------------------------------------- */\nexport const DefaultChannelActions: React.FC<ChannelActionsProps> = React.memo(({ channel, actions, onClose }) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n\n const handleActionsClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n setDropdownOpen(true);\n }, []);\n\n const handleClose = useCallback(() => {\n setDropdownOpen(false);\n setAnchorRect(null);\n onClose();\n }, [onClose]);\n\n if (!actions || actions.length === 0) return null;\n\n return (\n <>\n <button\n type=\"button\"\n className={`ermis-channel-list__actions-trigger ${dropdownOpen ? 'ermis-channel-list__actions-trigger--active' : ''}`}\n onClick={handleActionsClick}\n title=\"More actions\"\n >\n <MoreIcon />\n </button>\n <Dropdown\n isOpen={dropdownOpen}\n anchorRect={anchorRect}\n onClose={handleClose}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.map((action) => (\n <button\n key={action.id}\n className={`ermis-dropdown__item ${action.isDanger ? 'ermis-dropdown__item--danger' : ''}`}\n onClick={(e) => {\n e.stopPropagation();\n handleClose();\n action.onClick(channel, e);\n }}\n >\n {action.icon}\n <span>{action.label}</span>\n </button>\n ))}\n </div>\n </Dropdown>\n </>\n );\n});\n\nDefaultChannelActions.displayName = 'DefaultChannelActions';\n","import React, { useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\n\n// Global event name used to close any other open dropdowns\nconst CLOSE_ALL_EVENT = 'ermis:close-all-dropdowns';\n\n/** Dispatch a global event to close all open dropdowns */\nexport const closeAllDropdowns = () => {\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT));\n};\n\nexport interface DropdownProps {\n /** Whether the dropdown is open */\n isOpen: boolean;\n /** Rect from getBoundingClientRect() of the anchor element */\n anchorRect: DOMRect | null;\n /** Callback when dropdown requests to close (e.g., click outside, scroll, Escape) */\n onClose: () => void;\n /** Dropdown menu content */\n children: React.ReactNode;\n /** Horizontal alignment relative to the anchor. Default: 'left' */\n align?: 'left' | 'right';\n /** Optional custom CSS class for the container */\n className?: string;\n /** Optional custom CSS style for the container */\n style?: React.CSSProperties;\n}\n\nexport const Dropdown: React.FC<DropdownProps> = ({\n isOpen,\n anchorRect,\n onClose,\n children,\n align = 'left',\n className = '',\n style: propStyle = {},\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceId = useRef(Math.random().toString(36).slice(2));\n\n // Listen for global close event — only register when open to avoid N listeners\n useEffect(() => {\n if (!isOpen) return;\n\n // Broadcast: close all OTHER open dropdowns\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT, { detail: instanceId.current }));\n\n const handleGlobalClose = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (!detail || detail !== instanceId.current) {\n onClose();\n }\n };\n\n const handleClickOutside = (e: MouseEvent) => {\n // Allow the click to process if it's on a trigger button so it can toggle itself\n // We rely on the trigger stopping propagation or using the global close event.\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n\n const handleScroll = () => onClose();\n\n // Delay click listener to prevent instant close from the opening click\n const tid = setTimeout(() => {\n document.addEventListener('click', handleClickOutside);\n }, 10);\n\n document.addEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n\n return () => {\n clearTimeout(tid);\n document.removeEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.removeEventListener('click', handleClickOutside);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n };\n }, [isOpen, onClose]);\n\n if (!isOpen || !anchorRect) return null;\n\n const spaceBelow = window.innerHeight - anchorRect.bottom;\n const spaceAbove = anchorRect.top;\n const estimatedDropdownHeight = 250;\n\n let verticalStyle: React.CSSProperties = {};\n if (spaceBelow < estimatedDropdownHeight && spaceAbove > spaceBelow) {\n // Open upwards (bottom-aligned to the top of the trigger)\n verticalStyle = { bottom: window.innerHeight - anchorRect.top + 4 };\n } else {\n // Open downwards\n verticalStyle = { top: anchorRect.bottom + 4 };\n }\n\n const style: React.CSSProperties = {\n position: 'fixed',\n zIndex: 99999,\n ...verticalStyle,\n ...(align === 'right'\n ? { right: window.innerWidth - anchorRect.right }\n : { left: anchorRect.left }),\n ...propStyle\n };\n\n const portalTarget = document.querySelector('.ermis-chat') || document.body;\n\n return createPortal(\n <div ref={containerRef} className={`ermis-dropdown ${className}`.trim()} style={style}>\n {children}\n </div>,\n portalTarget\n );\n};\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { ForwardMessageModal } from './ForwardMessageModal';\nimport type { ChannelProps } from '../types';\n\nexport type { ChannelProps } from '../types';\n\nconst DefaultEmpty = React.memo(() => (\n <div className=\"ermis-channel__empty\">Select a channel to start chatting</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/**\n * Channel wrapper component.\n *\n * Customization:\n * - `HeaderComponent` — replace default ChannelHeader with a fully custom component.\n * Receives `{ channel, name, image }` as props.\n * - `EmptyStateIndicator` — custom component when no channel is selected.\n */\nexport const Channel: React.FC<ChannelProps> = React.memo(({\n children,\n className,\n EmptyStateIndicator = DefaultEmpty,\n HeaderComponent,\n ForwardMessageModalComponent = ForwardMessageModal,\n}) => {\n const { activeChannel, client, forwardingMessage, setForwardingMessage } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n\n // Force re-render when channel info is updated via WS\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n useEffect(() => {\n\n console.log('---activeChannel--', activeChannel)\n\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount((c) => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const headerData = useMemo(() => {\n if (!activeChannel || !HeaderComponent) return null;\n return {\n channel: activeChannel,\n name: (activeChannel.data?.name || activeChannel.cid || '') as string,\n image: activeChannel.data?.image as string | undefined,\n };\n }, [activeChannel, HeaderComponent, channelUpdateCount]);\n\n if (!activeChannel) {\n return <EmptyStateIndicator />;\n }\n\n const bannedClass = isBanned ? ' ermis-channel--banned' : '';\n const blockedClass = isBlocked ? ' ermis-channel--blocked' : '';\n\n return (\n <div className={`ermis-channel${bannedClass}${blockedClass}${className ? ` ${className}` : ''}`}>\n {HeaderComponent && headerData && <HeaderComponent {...headerData} />}\n {children}\n {forwardingMessage && (\n <ForwardMessageModalComponent\n message={forwardingMessage}\n onDismiss={() => setForwardingMessage(null)}\n />\n )}\n </div>\n );\n});\n\nChannel.displayName = 'Channel';\n\n","import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { createForwardMessagePayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { Modal } from './Modal';\nimport type { ForwardMessageModalProps, ForwardChannelItemProps, AvatarProps } from '../types';\nimport { isTopicChannel } from '../channelTypeUtils';\n\nexport type { ForwardMessageModalProps, ForwardChannelItemProps } from '../types';\n\n/* ----------------------------------------------------------\n Default channel item row with checkbox\n ---------------------------------------------------------- */\nconst DefaultForwardChannelItem: React.FC<ForwardChannelItemProps> = React.memo(({\n channel,\n selected,\n onToggle,\n AvatarComponent,\n}) => {\n const name = (channel.data?.name || channel.cid) as string;\n const rawImage = channel.data?.image as string | undefined;\n // Parse emoji:// format → extract just the emoji for avatar fallback\n const isEmoji = rawImage?.startsWith('emoji://');\n const image = isEmoji ? undefined : rawImage;\n const emojiIcon = isEmoji ? rawImage!.replace('emoji://', '') : undefined;\n\n return (\n <div\n className={`ermis-forward-modal__channel-item ${selected ? 'ermis-forward-modal__channel-item--selected' : ''}`}\n onClick={() => onToggle(channel)}\n >\n {emojiIcon ? (\n <span className=\"ermis-forward-modal__channel-emoji\" style={{ fontSize: 24, width: 36, textAlign: 'center' }}>{emojiIcon}</span>\n ) : (\n <AvatarComponent image={image} name={name} size={36} />\n )}\n <span className=\"ermis-forward-modal__channel-name\">{name}</span>\n <div className={`ermis-forward-modal__checkbox ${selected ? 'ermis-forward-modal__checkbox--checked' : ''}`}>\n {selected && (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n </div>\n </div>\n );\n});\nDefaultForwardChannelItem.displayName = 'DefaultForwardChannelItem';\n\n/* ----------------------------------------------------------\n ForwardMessageModal\n ---------------------------------------------------------- */\nexport const ForwardMessageModal: React.FC<ForwardMessageModalProps> = ({\n message,\n onDismiss,\n ChannelItemComponent = DefaultForwardChannelItem,\n SearchInputComponent,\n}) => {\n const { client, activeChannel } = useChatClient();\n const [selectedChannels, setSelectedChannels] = useState<Set<string>>(new Set());\n const [search, setSearch] = useState('');\n const [sending, setSending] = useState(false);\n const [results, setResults] = useState<{ success: string[]; failed: string[] } | null>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n\n /* ---------- Get channels from client state (exclude topics) ---------- */\n const channels = useMemo(() => {\n return (Object.values(client.activeChannels) as Channel[]).filter(\n (ch) => !isTopicChannel(ch),\n );\n }, [client.activeChannels]);\n\n /* ---------- Filter by search ---------- */\n const filteredChannels = useMemo(() => {\n if (!search.trim()) return channels;\n const q = search.toLowerCase();\n return channels.filter((ch) => {\n const name = ((ch.data?.name || ch.cid) as string).toLowerCase();\n return name.includes(q);\n });\n }, [channels, search]);\n\n /* ---------- Toggle selection ---------- */\n const toggleChannel = useCallback((channel: Channel) => {\n setSelectedChannels((prev) => {\n const next = new Set(prev);\n if (next.has(channel.cid)) {\n next.delete(channel.cid);\n } else {\n next.add(channel.cid);\n }\n return next;\n });\n }, []);\n\n /* ---------- Send forward ---------- */\n const handleSend = useCallback(async () => {\n if (!activeChannel || selectedChannels.size === 0 || sending) return;\n setSending(true);\n const success: string[] = [];\n const failed: string[] = [];\n\n for (const cid of selectedChannels) {\n const targetChannel = channels.find((c) => c.cid === cid);\n if (!targetChannel) continue;\n try {\n const forwardPayload = createForwardMessagePayload(\n message,\n targetChannel.cid as string,\n activeChannel.cid as string,\n );\n\n await activeChannel.forwardMessage(forwardPayload, {\n type: targetChannel.type,\n channelID: targetChannel.id!,\n });\n success.push((targetChannel.data?.name || targetChannel.cid) as string);\n } catch (err) {\n console.error(`Failed to forward to ${cid}`, err);\n failed.push((targetChannel.data?.name || targetChannel.cid) as string);\n }\n }\n\n setResults({ success, failed });\n setSending(false);\n\n // Auto-close after success (short delay)\n if (failed.length === 0) {\n setTimeout(() => onDismiss(), 1200);\n }\n }, [activeChannel, selectedChannels, channels, message, sending, onDismiss]);\n\n /* ---------- Keyboard / backdrop close ---------- */\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onDismiss();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [onDismiss]);\n\n const handleBackdropClick = useCallback((e: React.MouseEvent) => {\n if (e.target === backdropRef.current) onDismiss();\n }, [onDismiss]);\n\n /* ---------- Message preview ---------- */\n const previewText = message.text\n ? (message.text.length > 120 ? message.text.slice(0, 120) + '…' : message.text)\n : '';\n const attachmentCount = message.attachments?.length ?? 0;\n\n const footer = (\n <>\n <button className=\"ermis-forward-modal__btn ermis-forward-modal__btn--cancel\" onClick={onDismiss}>\n Cancel\n </button>\n <button\n className=\"ermis-forward-modal__btn ermis-forward-modal__btn--send\"\n onClick={handleSend}\n disabled={selectedChannels.size === 0 || sending || results !== null}\n >\n {sending ? 'Sending…' : `Forward${selectedChannels.size > 0 ? ` (${selectedChannels.size})` : ''}`}\n </button>\n </>\n );\n\n return (\n <Modal isOpen onClose={onDismiss} title=\"Forward Message\" footer={footer}>\n {/* Message preview */}\n <div className=\"ermis-forward-modal__preview\">\n <div className=\"ermis-forward-modal__preview-sender\">\n {message.user?.name || message.user_id || 'Unknown'}\n </div>\n {previewText && (\n <div className=\"ermis-forward-modal__preview-text\">{previewText}</div>\n )}\n {attachmentCount > 0 && (\n <div className=\"ermis-forward-modal__preview-attachments\">\n 📎 {attachmentCount} attachment{attachmentCount > 1 ? 's' : ''}\n </div>\n )}\n </div>\n\n {/* Search */}\n <div className=\"ermis-forward-modal__search-wrapper\">\n {SearchInputComponent ? (\n <SearchInputComponent value={search} onChange={setSearch} />\n ) : (\n <input\n className=\"ermis-forward-modal__search\"\n type=\"text\"\n placeholder=\"Search channels…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n autoFocus\n />\n )}\n </div>\n\n {/* Channel list */}\n <div className=\"ermis-forward-modal__channel-list\">\n {filteredChannels.length === 0 ? (\n <div className=\"ermis-forward-modal__empty\">No channels found</div>\n ) : (\n filteredChannels.map((ch) => (\n <ChannelItemComponent\n key={ch.cid}\n channel={ch}\n selected={selectedChannels.has(ch.cid)}\n onToggle={toggleChannel}\n AvatarComponent={Avatar}\n />\n ))\n )}\n </div>\n\n {/* Results feedback */}\n {results && (\n <div className=\"ermis-forward-modal__results\">\n {results.success.length > 0 && (\n <div className=\"ermis-forward-modal__results-success\">\n ✓ Sent to {results.success.join(', ')}\n </div>\n )}\n {results.failed.length > 0 && (\n <div className=\"ermis-forward-modal__results-failed\">\n ✗ Failed: {results.failed.join(', ')}\n </div>\n )}\n </div>\n )}\n </Modal>\n );\n};\n","import React, { useMemo, useState, useEffect, useContext } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelHeaderProps } from '../types';\nimport type { OnlineStatus } from '../hooks/useOnlineStatus';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport { hasTopicsEnabled, isDirectChannel } from '../channelTypeUtils';\nimport { isSkippedMember, isFriendChannel } from '../channelRoleUtils';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\n\nexport type { ChannelHeaderProps } from '../types';\n\n/**\n * ChannelHeader displays the active channel's avatar and name.\n *\n * Customization:\n * - `title` / `image` — override the channel name and avatar\n * - `subtitle` — add a subtitle line (e.g. member count)\n * - `AvatarComponent` — replace the avatar\n * - `renderTitle(channel)` — fully custom title rendering\n * - `renderRight(channel)` — render content on the right side\n * - `showOnlineStatus` — show online/offline dot for friend channels (default: true)\n * - `OnlineIndicatorComponent` — replace the default indicator\n *\n * For a fully custom header, use `Channel`'s `HeaderComponent` prop instead.\n */\nexport const ChannelHeader: React.FC<ChannelHeaderProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n title,\n image,\n subtitle,\n renderRight,\n renderTitle,\n renderAudioCallButton,\n renderVideoCallButton,\n audioCallTitle = 'Audio Call',\n videoCallTitle = 'Video Call',\n CallBadgeComponent,\n showOnlineStatus = true,\n onlineLabel = 'Online',\n offlineLabel = 'Offline',\n OnlineIndicatorComponent,\n}) => {\n const { activeChannel, client, enableCall } = useChatClient();\n const { isPending } = usePendingState(activeChannel, client.userID);\n const callContext = useContext(ErmisCallContext);\n\n const isSkipped = client.userID \n ? isSkippedMember(activeChannel?.state?.members?.[client.userID]?.channel_role as string) || \n isSkippedMember(activeChannel?.state?.membership?.channel_role as string)\n : false;\n\n const actionDisabled = isPending || isSkipped;\n\n // Force re-render when channel.updated WS event fires\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount(c => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelName = useMemo(() =>\n title || activeChannel?.data?.name || activeChannel?.cid || '',\n [title, activeChannel?.data?.name, activeChannel?.cid, channelUpdateCount],\n );\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelImage = useMemo(() =>\n image || (activeChannel?.data?.image as string | undefined),\n [image, activeChannel?.data?.image, channelUpdateCount],\n );\n\n const teamName = useMemo(() => {\n if (!activeChannel) return undefined;\n \n // If it's a topic, derive from parent_cid\n const parentCid = activeChannel.data?.parent_cid as string | undefined;\n if (parentCid && client.activeChannels[parentCid]) {\n return client.activeChannels[parentCid].data?.name || client.activeChannels[parentCid].cid;\n }\n\n // If it's a topics-enabled team channel (the general proxy), the proxy overrides data.name.\n // We can pull the original name from the SDK cache.\n if (hasTopicsEnabled(activeChannel)) {\n const rawChannel = client.activeChannels[activeChannel.cid];\n if (rawChannel && rawChannel.data?.name && rawChannel.data.name !== activeChannel.data?.name) {\n return rawChannel.data.name;\n }\n }\n \n return undefined;\n }, [activeChannel, client.activeChannels]);\n\n // ── Online Status (direct friend channels only) ──\n const currentUserId = client.userID;\n\n // Get the \"other\" user's ID from the direct channel.\n const otherUserId = useMemo(() => {\n if (!activeChannel || !currentUserId || !isDirectChannel(activeChannel)) return undefined;\n const members = activeChannel.state?.members;\n if (!members) return undefined;\n for (const memberId of Object.keys(members)) {\n if (memberId !== currentUserId) return memberId;\n }\n return undefined;\n }, [activeChannel, currentUserId]);\n\n // Check if this is a friend channel (both members are owner).\n const isFriend = useMemo(() => {\n if (!otherUserId || !currentUserId || !activeChannel) return false;\n return isFriendChannel(activeChannel, otherUserId, currentUserId);\n }, [activeChannel, otherUserId, currentUserId]);\n\n // Derive online status from watchers + subscribe to realtime events.\n const [onlineStatus, setOnlineStatus] = useState<OnlineStatus>('unknown');\n\n useEffect(() => {\n if (!showOnlineStatus || !isFriend || !otherUserId || !activeChannel) {\n setOnlineStatus('unknown');\n return;\n }\n\n // Read initial state from watchers.\n setOnlineStatus(activeChannel.state?.watchers?.[otherUserId] ? 'online' : 'offline');\n\n const handleWatchingStart = (event: Event) => {\n if (event.user?.id === otherUserId) {\n setOnlineStatus('online');\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n if (event.user?.id === otherUserId) {\n setOnlineStatus('offline');\n }\n };\n\n const sub1 = activeChannel.on('user.watching.start', handleWatchingStart);\n const sub2 = activeChannel.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [activeChannel, otherUserId, isFriend, showOnlineStatus]);\n\n const showOnlineDot = showOnlineStatus && onlineStatus !== 'unknown';\n const isOnline = onlineStatus === 'online';\n\n if (!activeChannel) return null;\n\n return (\n <div className={`ermis-channel-header${className ? ` ${className}` : ''}`}>\n {activeChannel.data?.parent_cid ? (\n <div className=\"ermis-channel-header__topic-avatar\">\n {channelImage && typeof channelImage === 'string' && channelImage.startsWith('emoji://') \n ? channelImage.replace('emoji://', '') \n : '#'}\n </div>\n ) : (\n <AvatarComponent image={channelImage} name={teamName || channelName} size={32} />\n )}\n\n <div className=\"ermis-channel-header__info\">\n {renderTitle ? (\n renderTitle(activeChannel)\n ) : (\n <div className=\"ermis-channel-header__title-container\">\n {teamName && (\n <div className=\"ermis-channel-header__team-name\">\n {teamName}\n </div>\n )}\n <div className=\"ermis-channel-header__name\">{channelName}</div>\n </div>\n )}\n {/* Online/Offline indicator for friend direct channels */}\n {showOnlineDot && (\n OnlineIndicatorComponent ? (\n <OnlineIndicatorComponent isOnline={isOnline} />\n ) : (\n <div className={`ermis-channel-header__online-status ermis-channel-header__online-status--${isOnline ? 'online' : 'offline'}`}>\n <span className={`ermis-channel-header__online-dot ermis-channel-header__online-dot--${isOnline ? 'online' : 'offline'}`} />\n <span className=\"ermis-channel-header__online-label\">\n {isOnline ? onlineLabel : offlineLabel}\n </span>\n </div>\n )\n )}\n {/* Consumer-provided subtitle (takes over if set) */}\n {subtitle && !showOnlineDot && (\n <div className=\"ermis-channel-header__subtitle\">{subtitle}</div>\n )}\n </div>\n\n {/* renderRight exposes actionDisabled for consumers to disable UI features natively */}\n <div className=\"ermis-channel-header__actions\">\n {enableCall && callContext && isDirectChannel(activeChannel) && !isPending && !isSkipped && (\n <>\n {renderAudioCallButton ? (\n renderAudioCallButton(() => callContext.createCall('audio', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('audio', activeChannel.cid || '')}\n title={audioCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n </button>\n )}\n \n {renderVideoCallButton ? (\n renderVideoCallButton(() => callContext.createCall('video', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('video', activeChannel.cid || '')}\n title={videoCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n </button>\n )}\n </>\n )}\n {/* C8: Active call badge */}\n {enableCall && callContext && callContext.callStatus && CallBadgeComponent && (\n <CallBadgeComponent callType={callContext.callType} />\n )}\n {renderRight && renderRight(activeChannel, actionDisabled)}\n </div>\n </div>\n );\n});\n\nChannelHeader.displayName = 'ChannelHeader';\n","import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';\nimport { VList, type VListHandle } from 'virtua';\nimport type { MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useLoadMessages } from '../hooks/useLoadMessages';\nimport { useScrollToMessage } from '../hooks/useScrollToMessage';\nimport { useChannelMessages } from '../hooks/useChannelMessages';\nimport { useChannelProfile } from '../hooks/useChannelData';\nimport { Avatar } from './Avatar';\nimport { MessageItem } from './MessageItem';\nimport { SystemMessageItem } from './MessageItem';\nimport { isPublicGroupChannel, isDirectChannel } from '../channelTypeUtils';\nimport { canManageChannel, isSkippedMember, isPendingMember } from '../channelRoleUtils';\nimport {\n defaultMessageRenderers,\n type MessageBubbleProps,\n} from './MessageRenderers';\nimport { getDateKey, formatDateLabel, getMessageUserId, formatReadTimestamp } from '../utils';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { PinnedMessages } from './PinnedMessages';\nimport { ReadReceipts } from './ReadReceipts';\nimport { TypingIndicator } from './TypingIndicator';\nimport { PendingOverlay } from './PendingOverlay';\nimport { SkippedOverlay } from './SkippedOverlay';\nimport { BannedOverlay } from './BannedOverlay';\nimport { ClosedTopicOverlay } from './ClosedTopicOverlay';\nimport type { MessageListProps } from '../types';\n\n/* ----------------------------------------------------------\n Internal sub-components\n ---------------------------------------------------------- */\nconst DefaultDateSeparator: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-message-list__date-separator\">\n <div className=\"ermis-message-list__date-separator-line\" />\n <span className=\"ermis-message-list__date-separator-label\">{label}</span>\n <div className=\"ermis-message-list__date-separator-line\" />\n </div>\n));\n(DefaultDateSeparator as any).displayName = 'DefaultDateSeparator';\n\nconst DefaultJumpToLatest = React.memo(({ onClick, label = '↓ Jump to latest' }: any) => (\n <button className=\"ermis-message-list__jump-latest\" onClick={onClick}>\n {label}\n </button>\n));\nDefaultJumpToLatest.displayName = 'DefaultJumpToLatest';\n\nconst DefaultEmpty = React.memo(({ title = 'No messages yet', subtitle = 'Send a message to start the conversation' }: any) => (\n <div className=\"ermis-message-list__empty\">\n <div className=\"ermis-message-list__empty-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__empty-title\">{title}</span>\n <span className=\"ermis-message-list__empty-subtitle\">{subtitle}</span>\n </div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\nconst DefaultBubble: React.FC<MessageBubbleProps> = React.memo(({\n isOwnMessage,\n message,\n children,\n}) => (\n <div\n className={`ermis-message-bubble ${isOwnMessage ? 'ermis-message-bubble--own' : 'ermis-message-bubble--other'}`}\n >\n {message?.pinned && (\n <div className={`ermis-message-list__pinned-indicator ${isOwnMessage ? 'ermis-message-list__pinned-indicator--own' : 'ermis-message-list__pinned-indicator--other'}`}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </div>\n )}\n {children}\n </div>\n));\n(DefaultBubble as any).displayName = 'DefaultBubble';\n\nconst DefaultPendingInviteeNotification = React.memo(({ inviteeName, label }: { inviteeName?: string, label?: string }) => {\n const defaultLabel = inviteeName ? `${inviteeName} needs to accept your invitation to see the messages you've sent` : 'The invited user needs to accept your invitation to see the messages you\\'ve sent';\n return (\n <div className=\"ermis-message-list__pending-invitee\">\n <div className=\"ermis-message-list__pending-invitee-content\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n <span>{label || defaultLabel}</span>\n </div>\n </div>\n );\n});\nDefaultPendingInviteeNotification.displayName = 'DefaultPendingInviteeNotification';\n\n/* ----------------------------------------------------------\n VirtualMessageList\n ---------------------------------------------------------- */\nexport const VirtualMessageList: React.FC<MessageListProps> = React.memo(({\n renderMessage,\n className,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n MessageBubble = DefaultBubble,\n messageRenderers: customRenderers,\n loadMoreLimit = 25,\n DateSeparatorComponent = DefaultDateSeparator,\n MessageItemComponent = MessageItem,\n SystemMessageItemComponent = SystemMessageItem,\n JumpToLatestButton = DefaultJumpToLatest,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent,\n showPinnedMessages = true,\n PinnedMessagesComponent = PinnedMessages,\n showReadReceipts = true,\n ReadReceiptsComponent = ReadReceipts,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars = 5,\n showTypingIndicator = true,\n TypingIndicatorComponent = TypingIndicator,\n MessageReactionsComponent,\n emptyTitle = 'No messages yet',\n emptySubtitle = 'Send a message to start the conversation',\n jumpToLatestLabel = '↓ Jump to latest',\n bannedOverlayTitle = 'You have been banned from this channel',\n bannedOverlaySubtitle = 'You can no longer read or send messages here',\n blockedOverlayTitle = 'You have blocked this user',\n blockedOverlaySubtitle = 'Unblock to continue the conversation',\n pendingOverlayTitle = 'You are invited to this channel',\n pendingOverlaySubtitle = 'Accept the invitation to view messages and interact',\n pendingAcceptLabel = 'Accept',\n pendingRejectLabel = 'Reject',\n pendingSkipLabel = 'Skip',\n skippedOverlayTitle = 'You skipped this conversation',\n skippedOverlaySubtitle = 'Accept the invitation to start chatting',\n skippedAcceptLabel = 'Accept',\n closedTopicOverlayTitle = 'This topic has been closed',\n closedTopicOverlaySubtitle = 'You can no longer read or send messages in this topic.',\n closedTopicReopenLabel = 'Reopen Topic',\n PendingInviteeNotificationComponent = DefaultPendingInviteeNotification,\n pendingInviteeLabel,\n}) => {\n const { client, messages, readState, activeChannel, setActiveChannel, jumpToMessageId, setJumpToMessageId } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n \n const isSkipped = client.userID \n ? isSkippedMember(activeChannel?.state?.members?.[client.userID]?.channel_role as string) || \n isSkippedMember(activeChannel?.state?.membership?.channel_role as string)\n : false;\n\n const isClosedTopic = activeChannel?.data?.is_closed_topic === true;\n const parentCid = activeChannel?.data?.parent_cid as string | undefined;\n const parentChannel = parentCid && client ? client.activeChannels[parentCid] : undefined;\n\n const { channelName, channelImage } = useChannelProfile(activeChannel);\n\n const vlistRef = useRef<VListHandle>(null);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const currentUserId = client.userID;\n const currentUserRole = currentUserId ? activeChannel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const canManageTopic = canManageChannel(currentUserRole);\n\n const pendingInviteeName = useMemo(() => {\n if (!activeChannel || !currentUserId) return null;\n if (!isDirectChannel(activeChannel)) return null;\n const membersList = Object.values(activeChannel.state?.members || {});\n if (membersList.length === 2 && !isPending) {\n const otherUser = membersList.find(m => m.user_id !== currentUserId);\n if (otherUser && isPendingMember(otherUser.channel_role)) {\n return otherUser.user?.name || otherUser.user?.id || 'User';\n }\n }\n return null;\n }, [activeChannel, currentUserId, isPending]);\n\n // Ref to scope DOM queries (safe for multiple instances)\n const containerRef = useRef<HTMLDivElement>(null);\n const getVListElement = useCallback((): HTMLElement | null => {\n return containerRef.current?.querySelector('.ermis-message-list__vlist') ?? null;\n }, []);\n\n const handleAcceptInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n const isPublicTeamOrMeeting = isPublicGroupChannel(activeChannel);\n const action = isPublicTeamOrMeeting ? 'join' : 'accept';\n await activeChannel.acceptInvite(action);\n } catch (e: any) {\n console.error('Error accepting invite', e);\n }\n }, [activeChannel]);\n\n const handleRejectInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.rejectInvite();\n if (setActiveChannel) setActiveChannel(null);\n } catch (e: any) {\n console.error('Error rejecting invite', e);\n }\n }, [activeChannel, setActiveChannel]);\n\n const handleSkipInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.skipInvite();\n if (setActiveChannel) setActiveChannel(null);\n } catch (e: any) {\n console.error('Error skipping invite', e);\n }\n }, [activeChannel, setActiveChannel]);\n\n const scrollToBottom = useCallback((smooth = false, attempts = 0) => {\n const handle = vlistRef.current;\n if (!handle) return;\n\n const count = messagesRef.current.length;\n if (count === 0) return;\n\n // Ensure virtua has measured the viewport via ResizeObserver.\n // If viewportSize is unmeasured (0) or scrollSize is 0, align: 'end' calculates wrong.\n if ((!handle.viewportSize || handle.viewportSize === 0) && attempts < 10) {\n requestAnimationFrame(() => scrollToBottom(smooth, attempts + 1));\n return;\n }\n\n handle.scrollToIndex(count - 1, { align: 'end', smooth });\n }, []);\n\n // Shared guard: skip scroll-triggered loads during jump transitions\n const jumpingRef = useRef(false);\n\n /* ---------- Hooks ---------- */\n const {\n shiftMode,\n hasMore, setHasMore,\n hasNewer, setHasNewer,\n loadingMoreRef, loadingNewerRef,\n handleScroll,\n isAtBottomRef,\n } = useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n loadMoreLimit,\n });\n\n const { highlightedId, scrollToMessage, jumpToLatest } = useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n });\n\n // React to jumpToMessageId from context (e.g. search panel)\n useEffect(() => {\n if (jumpToMessageId) {\n scrollToMessage(jumpToMessageId);\n setJumpToMessageId(null);\n }\n }, [jumpToMessageId, scrollToMessage, setJumpToMessageId]);\n\n useChannelMessages({\n scrollToBottom,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch: useCallback(() => {\n setHasMore(true);\n setHasNewer(false);\n loadingMoreRef.current = false;\n loadingNewerRef.current = false;\n }, [setHasMore, setHasNewer]),\n });\n\n const hasOverlay = Boolean(isClosedTopic || isPending || isBanned || isBlocked || isSkipped);\n const prevOverlayRef = useRef(hasOverlay);\n\n useEffect(() => {\n if (prevOverlayRef.current && !hasOverlay) {\n // Transitioned from having an overlay to normal view.\n // Give VList a moment to measure its new DOM size via ResizeObserver, then jump to the bottom.\n setTimeout(() => scrollToBottom(false), 50);\n setTimeout(() => scrollToBottom(false), 200);\n setTimeout(() => scrollToBottom(false), 500);\n }\n prevOverlayRef.current = hasOverlay;\n }, [hasOverlay, scrollToBottom]);\n\n const renderers = useMemo(\n () => ({ ...defaultMessageRenderers, ...customRenderers }),\n [customRenderers],\n );\n\n /* ---------- Compute read-by map (message.id → readers) ---------- */\n const readByMap = useMemo(() => {\n const map: Record<string, Array<{ id: string; name?: string; avatar?: string; last_read?: Date | string }>> = {};\n if (!readState) return map;\n for (const userId of Object.keys(readState)) {\n if (userId === currentUserId) continue; // exclude self\n const entry = readState[userId];\n if (entry.last_read_message_id) {\n if (!map[entry.last_read_message_id]) {\n map[entry.last_read_message_id] = [];\n }\n map[entry.last_read_message_id].push({\n id: userId,\n name: entry.user?.name,\n avatar: entry.user?.avatar,\n last_read: entry.last_read,\n });\n }\n }\n return map;\n }, [readState, currentUserId]);\n\n /* ---------- Memoized message elements ---------- */\n const messageElements = useMemo(() => {\n return messages.map((message, index) => {\n const isOwnMessage =\n message.user_id === currentUserId || message.user?.id === currentUserId;\n const messageType = (message.type || 'regular') as MessageLabel;\n\n // Date separator\n const prevMsg = index > 0 ? messages[index - 1] : null;\n const showDateSeparator =\n !prevMsg || getDateKey(message.created_at) !== getDateKey(prevMsg.created_at);\n const dateSeparator = showDateSeparator ? (\n <DateSeparatorComponent label={formatDateLabel(message.created_at)} />\n ) : null;\n\n if (renderMessage) {\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <div>{renderMessage(message, isOwnMessage)}</div>\n </div>\n );\n }\n\n if (messageType === 'system') {\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <SystemMessageItemComponent\n message={message}\n isOwnMessage={isOwnMessage}\n SystemRenderer={renderers.system}\n />\n </div>\n );\n }\n\n // Message grouping\n const prevType = (prevMsg?.type || 'regular') as MessageLabel;\n const isFirstInGroup =\n showDateSeparator ||\n !prevMsg ||\n prevType === 'system' ||\n prevType === 'signal' ||\n getMessageUserId(prevMsg) !== getMessageUserId(message);\n\n const nextMsg = index < messages.length - 1 ? messages[index + 1] : null;\n const nextType = (nextMsg?.type || 'regular') as MessageLabel;\n const nextShowDateSeparator = nextMsg\n ? getDateKey(nextMsg.created_at) !== getDateKey(message.created_at)\n : false;\n\n const isLastInGroup =\n !nextMsg ||\n nextShowDateSeparator ||\n nextType === 'system' ||\n nextType === 'signal' ||\n getMessageUserId(nextMsg) !== getMessageUserId(message);\n\n const MessageRenderer = renderers[messageType] || renderers.regular;\n\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <MessageItemComponent\n message={message}\n isOwnMessage={isOwnMessage}\n isFirstInGroup={isFirstInGroup}\n isLastInGroup={isLastInGroup}\n isHighlighted={highlightedId === message.id}\n AvatarComponent={AvatarComponent}\n MessageBubble={MessageBubble}\n MessageRenderer={MessageRenderer}\n onClickQuote={scrollToMessage}\n QuotedMessagePreviewComponent={QuotedMessagePreviewComponent}\n MessageActionsBoxComponent={MessageActionsBoxComponent}\n MessageReactionsComponent={MessageReactionsComponent}\n />\n {/* Read receipts — full width, right-aligned */}\n {showReadReceipts && (\n <ReadReceiptsComponent\n readers={readByMap[message.id!] || []}\n maxAvatars={readReceiptsMaxAvatars}\n AvatarComponent={AvatarComponent}\n TooltipComponent={ReadReceiptsTooltipComponent}\n isOwnMessage={isOwnMessage}\n isLastInGroup={isLastInGroup}\n status={message.status}\n />\n )}\n </div>\n );\n });\n }, [\n messages,\n currentUserId,\n highlightedId,\n renderers,\n renderMessage,\n AvatarComponent,\n MessageBubble,\n scrollToMessage,\n DateSeparatorComponent,\n MessageItemComponent,\n SystemMessageItemComponent,\n QuotedMessagePreviewComponent,\n MessageActionsBoxComponent,\n MessageReactionsComponent,\n readByMap,\n showReadReceipts,\n ReadReceiptsComponent,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars,\n ]);\n\n if (isBanned || isBlocked) {\n return (\n <BannedOverlay\n isBlocked={isBlocked}\n blockedTitle={blockedOverlayTitle}\n bannedTitle={bannedOverlayTitle}\n blockedSubtitle={blockedOverlaySubtitle}\n bannedSubtitle={bannedOverlaySubtitle}\n onUnblock={() => { activeChannel?.unblockUser().catch((e: any) => console.error('Error unblocking user', e)); }}\n />\n );\n }\n\n if (isPending) {\n const isDirect = activeChannel ? isDirectChannel(activeChannel) : false;\n return (\n <PendingOverlay\n channelImage={channelImage}\n channelName={channelName}\n title={pendingOverlayTitle}\n subtitle={pendingOverlaySubtitle}\n rejectLabel={pendingRejectLabel}\n acceptLabel={pendingAcceptLabel}\n onReject={handleRejectInvite}\n onAccept={handleAcceptInvite}\n skipLabel={isDirect ? pendingSkipLabel : undefined}\n onSkip={isDirect ? handleSkipInvite : undefined}\n AvatarComponent={AvatarComponent}\n />\n );\n }\n\n if (isSkipped) {\n return (\n <SkippedOverlay\n channelImage={channelImage}\n channelName={channelName}\n title={skippedOverlayTitle}\n subtitle={skippedOverlaySubtitle}\n acceptLabel={skippedAcceptLabel}\n onAccept={handleAcceptInvite}\n AvatarComponent={AvatarComponent}\n />\n );\n }\n\n if (isClosedTopic) {\n return (\n <ClosedTopicOverlay\n title={closedTopicOverlayTitle}\n subtitle={closedTopicOverlaySubtitle}\n canManageTopic={Boolean(canManageTopic && activeChannel && parentChannel)}\n reopenLabel={closedTopicReopenLabel}\n onReopen={() => { parentChannel?.reopenTopic(activeChannel!.cid).catch((e: any) => console.error('Error reopening topic', e)); }}\n />\n );\n }\n\n return (\n <div ref={containerRef} className={`ermis-message-list${className ? ` ${className}` : ''}`}>\n {showPinnedMessages && <PinnedMessagesComponent onClickMessage={scrollToMessage} AvatarComponent={AvatarComponent} />}\n\n {messages.length === 0 && (\n EmptyStateIndicator === DefaultEmpty\n ? <DefaultEmpty title={emptyTitle} subtitle={emptySubtitle} />\n : <EmptyStateIndicator />\n )}\n\n {pendingInviteeName && (\n <PendingInviteeNotificationComponent \n inviteeName={pendingInviteeName} \n label={typeof pendingInviteeLabel === 'function' ? pendingInviteeLabel(pendingInviteeName) : pendingInviteeLabel} \n />\n )}\n\n <VList\n key={activeChannel?.cid || 'empty'}\n ref={vlistRef}\n shift={shiftMode}\n onScroll={handleScroll}\n className=\"ermis-message-list__vlist\"\n >\n {messageElements}\n </VList>\n\n {/* Typing indicator */}\n {showTypingIndicator && <TypingIndicatorComponent />}\n\n {/* Jump to latest button */}\n {hasNewer && (\n JumpToLatestButton === DefaultJumpToLatest\n ? <DefaultJumpToLatest onClick={jumpToLatest} label={jumpToLatestLabel} />\n : <JumpToLatestButton onClick={jumpToLatest} />\n )}\n </div>\n );\n});\n\nVirtualMessageList.displayName = 'VirtualMessageList';\n","import { useState, useRef, useCallback, useEffect } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { useChatClient } from './useChatClient';\n\nconst LOAD_MORE_THRESHOLD = 200;\n\n/** Filter out messages whose id already exists in `existing` (or self-dedup if omitted). */\nexport const dedupMessages = (incoming: any[], existing?: any[]) => {\n const ids = new Set(existing?.map((m) => m.id) ?? []);\n return incoming.filter((m: any) => {\n if (!m.id || ids.has(m.id)) return false;\n ids.add(m.id);\n return true;\n });\n};\n\nexport type UseLoadMessagesOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n /** Shared guard ref — skip scroll-triggered loads during jump transitions */\n jumpingRef: React.MutableRefObject<boolean>;\n loadMoreLimit?: number;\n};\n\nexport type UseLoadMessagesReturn = {\n /** VList shift mode — true during prepend, auto-resets to false */\n shiftMode: boolean;\n hasMore: boolean;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n hasNewer: boolean;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n hasMoreRef: React.RefObject<boolean>;\n hasNewerRef: React.RefObject<boolean>;\n loadingMoreRef: React.MutableRefObject<boolean>;\n loadingNewerRef: React.MutableRefObject<boolean>;\n loadMore: () => Promise<void>;\n loadNewer: () => Promise<void>;\n handleScroll: (offset: number) => void;\n isAtBottomRef: React.MutableRefObject<boolean>;\n};\n\nexport function useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n loadMoreLimit = 25,\n}: UseLoadMessagesOptions): UseLoadMessagesReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [hasMore, setHasMore] = useState(true);\n const [hasNewer, setHasNewer] = useState(false);\n const [shiftMode, setShiftMode] = useState(false);\n\n // Auto-reset shiftMode after each prepend render\n useEffect(() => {\n if (shiftMode) {\n requestAnimationFrame(() => setShiftMode(false));\n }\n }, [shiftMode]);\n\n // Refs synced from state (avoid handleScroll recreation on state change)\n const hasMoreRef = useRef(true);\n hasMoreRef.current = hasMore;\n const hasNewerRef = useRef(false);\n hasNewerRef.current = hasNewer;\n const isAtBottomRef = useRef(true);\n\n // Concurrency guards\n const loadingMoreRef = useRef(false);\n const loadingNewerRef = useRef(false);\n\n const loadMore = useCallback(async () => {\n if (!activeChannel || loadingMoreRef.current) return;\n\n const currentMessages = messagesRef.current;\n const oldestMessage = currentMessages[0];\n if (!oldestMessage?.id) return;\n\n loadingMoreRef.current = true;\n try {\n const olderRaw = await activeChannel.queryMessagesLessThanId(oldestMessage.id, loadMoreLimit);\n\n if (olderRaw.length === 0) {\n setHasMore(false);\n return;\n }\n\n const olderFormatted = olderRaw.map((msg: any) => formatMessage(msg));\n setShiftMode(true);\n setMessages((prev) => {\n const unique = dedupMessages(olderFormatted, prev);\n if (unique.length === 0) {\n setHasMore(false);\n }\n return [...unique, ...prev];\n });\n } catch (err) {\n console.error('Failed to load more messages:', err);\n } finally {\n loadingMoreRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const loadNewer = useCallback(async () => {\n if (!activeChannel || loadingNewerRef.current) return;\n\n const currentMessages = messagesRef.current;\n const newestMessage = currentMessages[currentMessages.length - 1];\n if (!newestMessage?.id) return;\n\n loadingNewerRef.current = true;\n try {\n const newerRaw = await activeChannel.queryMessagesGreaterThanId(newestMessage.id, loadMoreLimit);\n\n if (newerRaw.length === 0) {\n setHasNewer(false);\n return;\n }\n\n const newerFormatted = newerRaw.map((msg: any) => formatMessage(msg));\n setMessages((prev) => {\n const unique = dedupMessages(newerFormatted, prev);\n if (unique.length === 0) {\n setHasNewer(false);\n }\n return [...prev, ...unique];\n });\n } catch (err) {\n console.error('Failed to load newer messages:', err);\n } finally {\n loadingNewerRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const handleScroll = useCallback(\n (offset: number) => {\n if (jumpingRef.current) return;\n const handle = vlistRef.current;\n if (!handle) return;\n const { scrollSize, viewportSize } = handle;\n\n const isBottom = Math.ceil(offset + viewportSize) >= scrollSize - 20;\n isAtBottomRef.current = isBottom;\n\n // Skip if content doesn't fill the viewport\n if (scrollSize <= viewportSize) {\n isAtBottomRef.current = true;\n return;\n }\n\n if (offset <= LOAD_MORE_THRESHOLD && hasMoreRef.current) {\n loadMore();\n }\n\n if (offset + viewportSize >= scrollSize - LOAD_MORE_THRESHOLD && hasNewerRef.current) {\n loadNewer();\n }\n },\n [loadMore, loadNewer],\n );\n\n return {\n shiftMode,\n hasMore,\n setHasMore,\n hasNewer,\n setHasNewer,\n hasMoreRef,\n hasNewerRef,\n loadingMoreRef,\n loadingNewerRef,\n loadMore,\n loadNewer,\n handleScroll,\n isAtBottomRef,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { dedupMessages } from './useLoadMessages';\nimport { useChatClient } from './useChatClient';\n\nexport type UseScrollToMessageOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n /** Getter to access the VList DOM element (scoped to container) */\n getVListElement: () => HTMLElement | null;\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during jumps */\n jumpingRef: React.MutableRefObject<boolean>;\n};\n\nexport type UseScrollToMessageReturn = {\n highlightedId: string | null;\n scrollToMessage: (messageId: string) => void;\n jumpToLatest: () => void;\n};\n\nexport function useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n}: UseScrollToMessageOptions): UseScrollToMessageReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [highlightedId, setHighlightedId] = useState<string | null>(null);\n const highlightTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Cleanup highlight timer on unmount\n useEffect(() => {\n return () => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n };\n }, []);\n\n const highlight = useCallback((messageId: string) => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n setHighlightedId(messageId);\n highlightTimerRef.current = setTimeout(() => {\n setHighlightedId(null);\n highlightTimerRef.current = null;\n }, 2500);\n }, []);\n\n const scrollToMessage = useCallback(\n async (messageId: string) => {\n // Prevent concurrent calls\n if (jumpingRef.current) return;\n\n // Case 1: message is already in current list\n const idx = messagesRef.current.findIndex((m) => m.id === messageId);\n if (idx !== -1) {\n vlistRef.current?.scrollToIndex(idx, { align: 'center', smooth: true });\n highlight(messageId);\n return;\n }\n\n // Case 2: message NOT in list — fetch around it\n if (!activeChannel) return;\n\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n try {\n const rawMessages = await activeChannel.queryMessagesAroundId(messageId, 25);\n if (!rawMessages || rawMessages.length === 0) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n const formatted = rawMessages.map((msg: any) => formatMessage(msg));\n const unique = dedupMessages(formatted);\n\n setHasMore(true);\n setHasNewer(true);\n setMessages(unique);\n\n // Wait for VList to render, then jump while hidden, then fade in\n setTimeout(() => {\n const newIdx = unique.findIndex((m: any) => m.id === messageId);\n if (newIdx === -1) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n vlistRef.current?.scrollToIndex(newIdx, { align: 'center' });\n\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n highlight(messageId);\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n } catch (err) {\n console.error('Failed to fetch messages around ID:', err);\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n }\n },\n [activeChannel, highlight, setMessages, setHasMore, setHasNewer, getVListElement],\n );\n\n const jumpToLatest = useCallback(() => {\n if (!activeChannel) return;\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n const latestMsgs = [...activeChannel.state.latestMessages];\n setMessages(latestMsgs);\n setHasNewer(false);\n setHasMore(true);\n\n setTimeout(() => {\n scrollToBottom(false);\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n }, [activeChannel, scrollToBottom, getVListElement, setMessages, setHasMore, setHasNewer]);\n\n return { highlightedId, scrollToMessage, jumpToLatest };\n}\n","import { useEffect, useCallback } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isPendingMember } from '../channelRoleUtils';\n\nexport type UseChannelMessagesOptions = {\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during channel switch */\n jumpingRef: React.MutableRefObject<boolean>;\n isAtBottomRef: React.MutableRefObject<boolean>;\n /** Called to reset load-more state when channel switches */\n onChannelSwitch?: () => void;\n};\n\n/**\n * Schedule multiple scroll-to-bottom attempts with increasing delays.\n * Handles content that changes height after initial render (images, embeds).\n */\nconst SCROLL_DELAYS = [50, 200, 500, 1000];\n\n/**\n * Subscribes to channel message events and handles:\n * - message.new → sync + scroll to bottom\n * - message.updated / message.deleted → sync only\n * - Channel switch → reset state + scroll to bottom\n */\nexport function useChannelMessages({\n scrollToBottom,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch,\n}: UseChannelMessagesOptions): void {\n const { client, activeChannel, syncMessages, setReadState } = useChatClient();\n\n const scheduleScrollToBottom = useCallback(\n (smooth: boolean) => {\n if (smooth) {\n // Trigger smooth scroll exactly once, otherwise browsers will\n // cancel the smooth animation if called multiple times in a row\n setTimeout(() => scrollToBottom(true), 100);\n } else {\n SCROLL_DELAYS.forEach((delay) => {\n setTimeout(() => scrollToBottom(false), delay);\n });\n }\n },\n [scrollToBottom],\n );\n\n useEffect(() => {\n if (!activeChannel) return;\n\n // Reset state for the new channel\n onChannelSwitch?.();\n\n // Manually force isAtBottom to true because we are jumping to the bottom.\n // jumpingRef blocks the resulting scroll event from updating isAtBottomRef,\n // so if it was false in the previous channel, it would stay false!\n isAtBottomRef.current = true;\n\n // Block scroll triggers during channel-switch scroll\n jumpingRef.current = true;\n // Defer scroll outside React lifecycle to avoid virtua flushSync warning\n setTimeout(() => {\n scrollToBottom(false);\n // Wait long enough for scrollToBottom's internal retries and the browser\n // to execute the scroll event\n setTimeout(() => {\n jumpingRef.current = false;\n }, 100);\n }, 0);\n\n const handleNewMessage = (event: Event) => {\n // Capture scroll state BEFORE sync causes re-render\n const wasAtBottom = isAtBottomRef.current;\n\n syncMessages();\n\n const isOwnMessage = event.message?.user?.id === client.userID || event.message?.user_id === client.userID;\n\n if (isOwnMessage || wasAtBottom) {\n scheduleScrollToBottom(true);\n }\n };\n\n const handleMessageChange = (_event: Event) => {\n syncMessages();\n };\n\n const handleMessageRead = (_event: Event) => {\n // SDK already updated channel.state.read — sync into React state\n setReadState({ ...activeChannel.state.read });\n };\n\n const handleUnblocked = (event: Event) => {\n // If the current user's block status was updated (meaning we unblocked someone)\n if (event.member?.user_id === client.userID) {\n // Refetch latest messages to fill in any missed during the block period\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessages();\n scheduleScrollToBottom(false);\n const isPending = isPendingMember(activeChannel.state?.membership?.channel_role as string);\n if (!isPending) {\n activeChannel.markRead().catch(() => {});\n }\n })\n .catch((e) => console.error('Failed to sync messages after unblock', e));\n }\n };\n\n const handleInviteAccepted = (event: Event) => {\n // Make sure the accepted invite corresponds to the actively opened channel\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as any).channel_id ? `${(event as any).channel_type}:${(event as any).channel_id}` : undefined);\n if (eventCid === activeChannel.cid) {\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessages();\n scheduleScrollToBottom(false);\n activeChannel.markRead().catch(() => {});\n })\n .catch((e) => console.error('Failed to sync messages after accepting invite', e));\n }\n };\n\n const client = activeChannel.getClient();\n const sub1 = activeChannel.on('message.new', handleNewMessage);\n const sub2 = activeChannel.on('message.updated', handleMessageChange);\n const sub3 = activeChannel.on('message.deleted', handleMessageChange);\n const sub4 = activeChannel.on('message.pinned', handleMessageChange);\n const sub5 = activeChannel.on('message.unpinned', handleMessageChange);\n const sub6 = activeChannel.on('message.read', handleMessageRead);\n const sub7 = activeChannel.on('message.deleted_for_me', handleMessageChange);\n const sub8 = activeChannel.on('reaction.new', handleMessageChange);\n const sub9 = activeChannel.on('reaction.deleted', handleMessageChange);\n const sub10 = activeChannel.on('member.unblocked', handleUnblocked);\n const sub11 = client.on('notification.invite_accepted', handleInviteAccepted);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n };\n }, [activeChannel, scrollToBottom, scheduleScrollToBottom, syncMessages, onChannelSwitch, setReadState]);\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\nexport const useChannelMembers = (channel: Channel | null | undefined) => {\n const [memberUpdateCount, setMemberUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateMembers = () => setMemberUpdateCount(c => c + 1);\n\n const sub1 = channel.on('member.added', updateMembers);\n const sub2 = channel.on('member.removed', updateMembers);\n const sub3 = channel.on('member.updated', updateMembers);\n const sub4 = channel.on('member.promoted', updateMembers);\n const sub5 = channel.on('member.demoted', updateMembers);\n const sub6 = channel.on('member.banned', updateMembers);\n const sub7 = channel.on('member.unbanned', updateMembers);\n const sub8 = channel.on('notification.invite_rejected', updateMembers);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n };\n }, [channel]);\n\n const membersArray = useMemo(() => {\n if (!channel?.state?.members) return [];\n return Object.values(channel.state.members) as Array<Record<string, unknown>>;\n }, [channel?.state?.members, memberUpdateCount]);\n\n return { members: membersArray, memberUpdateCount };\n};\n\nexport const useChannelProfile = (channel: Channel | null | undefined) => {\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateChannel = () => setChannelUpdateCount(c => c + 1);\n const sub = channel.on('channel.updated', updateChannel);\n return () => sub.unsubscribe();\n }, [channel]);\n\n const channelName = useMemo(() => channel?.data?.name || channel?.cid || 'Unknown Channel', [channel?.data?.name, channel?.cid, channel?.type, channelUpdateCount]);\n const channelImage = useMemo(() => channel?.data?.image as string | undefined, [channel?.data?.image, channelUpdateCount]);\n const channelDescription = useMemo(() => channel?.data?.description as string | undefined, [channel?.data?.description, channelUpdateCount]);\n\n return { channelName, channelImage, channelDescription };\n};\n","import React from 'react';\nimport type { MessageItemProps, SystemMessageItemProps } from '../types';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { MessageActionsBox } from './MessageActionsBox';\nimport { MessageReactions } from './MessageReactions';\nimport { MessageQuickReactions } from './MessageQuickReactions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { formatTime } from '../utils';\nimport { isSystemMessage } from '../messageTypeUtils';\n\nexport type { MessageItemProps, SystemMessageItemProps } from '../types';\n\n/* ----------------------------------------------------------\n MessageItem — single regular/signal message row\n ---------------------------------------------------------- */\n/* Inline status icon for own messages (sent / sending / error) */\nconst InlineStatusIcon: React.FC<{ status?: string; isOwnMessage: boolean; isLastInGroup: boolean }> = React.memo(({\n status,\n isOwnMessage,\n isLastInGroup,\n}) => {\n if (!isOwnMessage) return null;\n\n const isError = status === 'error' || status === 'failed_offline';\n if (!isLastInGroup && !isError) return null;\n\n if (isError) {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--failed\" title=\"Failed to send\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line>\n </svg>\n </span>\n );\n }\n\n if (status === 'sending') {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sending\" title=\"Sending...\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <polyline points=\"12 6 12 12 16 14\"></polyline>\n </svg>\n </span>\n );\n }\n\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sent\" title=\"Sent\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n </span>\n );\n});\nInlineStatusIcon.displayName = 'InlineStatusIcon';\n\nexport const MessageItem: React.FC<MessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n isFirstInGroup,\n isLastInGroup,\n isHighlighted,\n AvatarComponent,\n MessageBubble,\n MessageRenderer,\n onClickQuote,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent = MessageActionsBox,\n MessageReactionsComponent = MessageReactions,\n forwardedLabel = 'Forwarded',\n editedLabel = 'Edited',\n}) => {\n const { activeChannel, client } = useChatClient();\n const { hasCapability } = useChannelCapabilities();\n \n const canReact = hasCapability('send-reaction');\n\n const userName = message.user?.name || message.user_id;\n const userAvatar = message.user?.avatar;\n\n const quotedMessage = (message as any).quoted_message;\n const isForwarded = !!(message as any).forward_cid;\n const oldTexts = (message as any).old_texts;\n const isEdited = oldTexts && oldTexts.length > 0;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const handleReactionToggle = React.useCallback(async (type: string) => {\n if (!activeChannel || !canReact) return;\n const currentUserId = client?.userID;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some((r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n }, [activeChannel, message, client?.userID]);\n\n const statusClass =\n message.status === 'sending'\n ? 'ermis-message--sending'\n : (message.status === 'error' || message.status === 'failed_offline')\n ? 'ermis-message--error'\n : '';\n\n const isNewMessage = React.useMemo(() => {\n if (!message.created_at) return false;\n return Date.now() - new Date(message.created_at).getTime() < 1000;\n }, [message.created_at]);\n\n const itemClass = [\n 'ermis-message-list__item',\n isOwnMessage ? 'ermis-message-list__item--own' : 'ermis-message-list__item--other',\n isFirstInGroup ? 'ermis-message-list__item--group-start' : 'ermis-message-list__item--group-cont',\n isHighlighted ? 'ermis-message-list__item--highlighted' : '',\n isNewMessage ? 'ermis-message-list__item--new' : '',\n statusClass,\n ].filter(Boolean).join(' ');\n\n const contentClass = [\n 'ermis-message-list__item-content',\n hasAttachments ? 'ermis-message-list__item-content--has-attachments' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} data-message-id={message.id}>\n {/* Avatar area: show avatar only on first message, otherwise placeholder for alignment */}\n {!isOwnMessage && (\n <div className=\"ermis-message-list__item-avatar\">\n {isFirstInGroup\n ? <AvatarComponent image={userAvatar} name={userName} size={28} />\n : <div style={{ width: 28 }} />\n }\n </div>\n )}\n <div className={contentClass}>\n {!isOwnMessage && isFirstInGroup && (\n <span className=\"ermis-message-list__item-user\">{userName}</span>\n )}\n {/* Quoted message preview */}\n {quotedMessage && onClickQuote && (\n <QuotedMessagePreviewComponent\n quotedMessage={quotedMessage}\n isOwnMessage={isOwnMessage}\n onClick={onClickQuote}\n />\n )}\n <div className=\"ermis-message-list__bubble-wrapper\">\n <MessageQuickReactions message={message} isOwnMessage={isOwnMessage} disabled={!canReact} />\n <MessageBubble message={message} isOwnMessage={isOwnMessage}>\n {isForwarded && (\n <span className=\"ermis-message-list__forwarded-indicator\">{forwardedLabel}</span>\n )}\n <MessageRenderer message={message} isOwnMessage={isOwnMessage} />\n <span className=\"ermis-message-list__item-time\">\n {isEdited && (\n <span\n className=\"ermis-message-list__edited-indicator\"\n // data-tooltip={oldTexts.map((ot: any) => `[${formatTime(ot.created_at)}] ${ot.text}`).join('\\n')}\n >\n {editedLabel}\n </span>\n )}\n {formatTime(message.created_at)}\n <InlineStatusIcon status={message.status} isOwnMessage={isOwnMessage} isLastInGroup={isLastInGroup} />\n </span>\n </MessageBubble>\n\n {/* Actions: hover buttons + dropdown menu */}\n {!isSystemMessage(message) && (\n <MessageActionsBoxComponent\n message={message}\n isOwnMessage={isOwnMessage}\n />\n )}\n\n {/* Message Reactions */}\n {MessageReactionsComponent && (\n <MessageReactionsComponent\n reactionCounts={(message as any).reaction_counts}\n ownReactions={(message as any).own_reactions}\n latestReactions={(message as any).latest_reactions}\n onClickReaction={handleReactionToggle}\n disabled={!canReact}\n />\n )}\n </div>\n </div>\n </div>\n );\n});\nMessageItem.displayName = 'MessageItem';\n\n/* ----------------------------------------------------------\n SystemMessageItem — system/notification message row\n ---------------------------------------------------------- */\nexport const SystemMessageItem: React.FC<SystemMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n SystemRenderer,\n}) => (\n <div className=\"ermis-message-list__system\">\n <SystemRenderer message={message} isOwnMessage={isOwnMessage} />\n </div>\n));\nSystemMessageItem.displayName = 'SystemMessageItem';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { QuotedMessagePreviewProps } from '../types';\n\nexport type { QuotedMessagePreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 100;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\nexport const QuotedMessagePreview: React.FC<QuotedMessagePreviewProps> = React.memo(({\n quotedMessage,\n isOwnMessage,\n onClick,\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const authorName = quotedMessage.user?.name || quotedMessage.user?.id || 'Unknown';\n \n const rawText = quotedMessage.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, quotedMessage as any, userMap), [rawText, quotedMessage, userMap]);\n \n const previewText = formattedText\n ? truncateText(formattedText, MAX_PREVIEW_LENGTH)\n : 'Attachment';\n\n const handleClick = () => {\n onClick(quotedMessage.id);\n };\n\n return (\n <div\n className={`ermis-quoted-message ${isOwnMessage ? 'ermis-quoted-message--own' : ''}`}\n onClick={handleClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleClick();\n }}\n >\n <span className=\"ermis-quoted-message__author\">{authorName}</span>\n <span className=\"ermis-quoted-message__text\">{previewText}</span>\n </div>\n );\n});\n\nQuotedMessagePreview.displayName = 'QuotedMessagePreview';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useMessageActions } from '../hooks/useMessageActions';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { MessageActionsBoxProps } from '../types';\nimport { Dropdown, closeAllDropdowns } from './Dropdown';\n\n// Aliased for backward compatibility\nexport const closeAllActionBoxes = closeAllDropdowns;\n\nexport const MessageActionsBox: React.FC<MessageActionsBoxProps> = ({\n message,\n isOwnMessage,\n onReply: onReplyProp,\n onForward,\n onPinToggle,\n onEdit,\n onCopy,\n onDelete,\n onDeleteForMe,\n pinLabel = 'Pin',\n unpinLabel = 'Unpin',\n editLabel = 'Edit',\n copyLabel = 'Copy',\n deleteForMeLabel = 'Delete for me',\n deleteForEveryoneLabel = 'Delete for everyone',\n}) => {\n const { setQuotedMessage, setEditingMessage, setForwardingMessage, activeChannel } = useChatClient();\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null);\n const actions = useMessageActions(message, isOwnMessage);\n\n // Default handlers\n const onReply = onReplyProp ?? ((msg: FormatMessageResponse) => setQuotedMessage(msg));\n const onForwardHandler = onForward ?? ((msg: FormatMessageResponse) => setForwardingMessage(msg));\n const onPinToggleHandler = onPinToggle ?? (async (msg: FormatMessageResponse, isPinned: boolean) => {\n if (!activeChannel) return;\n try {\n if (isPinned) {\n await activeChannel.unpinMessage(msg.id!);\n } else {\n await activeChannel.pinMessage(msg.id!);\n }\n } catch (err) {\n console.error('Failed to toggle pin', err);\n }\n });\n const onEditHandler = onEdit ?? ((msg: FormatMessageResponse) => setEditingMessage(msg));\n\n const onDeleteForEveryoneHandler = onDelete ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessage(msg.id!);\n } catch (err) {\n console.error('Failed to delete message', err);\n }\n });\n\n const onDeleteForMeHandler = onDeleteForMe ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessageForMe(msg.id!);\n } catch (err) {\n console.error('Failed to delete message for me', err);\n }\n });\n\n const isOpen = anchorRect !== null;\n const onClose = useCallback(() => setAnchorRect(null), []);\n\n const handleMoreClick = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setAnchorRect(rect);\n };\n\n const handleCopy = async () => {\n if (onCopy) {\n onCopy(message);\n } else if (message.text) {\n try {\n await navigator.clipboard.writeText(message.text);\n } catch (err) {\n console.error('Failed to copy text:', err);\n }\n }\n onClose();\n };\n\n return (\n <>\n <div className={`ermis-message-list__actions ${isOpen ? 'ermis-message-list__actions--active' : ''}`}>\n {actions.canReply && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onReply?.(message)} \n title=\"Reply\"\n disabled={!actions.hasCapReply}\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M11.192 15.757c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L9.373 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.955 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53zm10.455 0c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L19.828 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.954 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53z\" />\n </svg>\n </button>\n )}\n {actions.canForward && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onForwardHandler(message)} \n title=\"Forward\"\n disabled={!actions.hasCapQuote}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 14 20 9 15 4\" />\n <path d=\"M4 20v-7a4 4 0 0 1 4-4h12\" />\n </svg>\n </button>\n )}\n <button\n className={`ermis-message-list__actions-trigger ${isOpen ? 'ermis-message-list__actions-trigger--active' : ''}`}\n onClick={handleMoreClick}\n title=\"More actions\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n </div>\n\n <Dropdown \n isOpen={isOpen} \n anchorRect={anchorRect} \n onClose={onClose} \n align={isOwnMessage ? 'right' : 'left'}\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.canPin && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onPinToggleHandler(message, actions.isPinned); onClose(); }}\n disabled={!actions.hasCapPin}\n >\n {actions.isPinned ? unpinLabel : pinLabel}\n </button>\n )}\n {actions.canEdit && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onEditHandler(message); onClose(); }}\n disabled={!actions.hasCapEdit}\n >\n {editLabel}\n </button>\n )}\n {actions.canCopy && (\n <button className=\"ermis-dropdown__item\" onClick={handleCopy}>\n {copyLabel}\n </button>\n )}\n\n {(actions.canDelete || actions.canDeleteForMe) && <div className=\"ermis-dropdown__divider\" />}\n\n {actions.canDeleteForMe && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForMeHandler(message); onClose(); }}\n disabled={!actions.hasCapDeleteForMe}\n >\n {deleteForMeLabel}\n </button>\n )}\n {actions.canDelete && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForEveryoneHandler(message); onClose(); }}\n disabled={!actions.hasCapDelete}\n >\n {deleteForEveryoneLabel}\n </button>\n )}\n </div>\n </Dropdown>\n </>\n );\n};\n","import { useMemo } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { useChannelCapabilities } from './useChannelCapabilities';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { isSignalMessage, isSystemMessage } from '../messageTypeUtils';\n\nexport type MessageActionList = {\n canEdit: boolean;\n canDelete: boolean;\n canDeleteForMe: boolean;\n canReply: boolean;\n canQuote: boolean;\n canForward: boolean;\n canPin: boolean;\n canCopy: boolean;\n isPinned: boolean;\n hasCapEdit: boolean;\n hasCapDelete: boolean;\n hasCapDeleteForMe: boolean;\n hasCapPin: boolean;\n hasCapReply: boolean;\n hasCapQuote: boolean;\n};\n\nexport const useMessageActions = (message: FormatMessageResponse, isOwnMessage: boolean): MessageActionList => {\n const { activeChannel, client } = useChatClient();\n const { isGroupChannel: isTeam, isOwner, hasCapability } = useChannelCapabilities();\n\n // Only depend on the specific message fields we actually read\n const messageType = message.type;\n const isPinnedFlag = message.pinned || !!message.pinned_at;\n\n return useMemo(() => {\n if (!activeChannel) {\n return {\n canEdit: false,\n canDelete: false,\n canDeleteForMe: false,\n canReply: false,\n canQuote: false,\n canForward: false,\n canPin: false,\n canCopy: false,\n isPinned: false,\n hasCapEdit: false,\n hasCapDelete: false,\n hasCapDeleteForMe: false,\n hasCapPin: false,\n hasCapReply: false,\n hasCapQuote: false,\n };\n }\n\n const isSystem = isSystemMessage(message);\n const isSignal = isSignalMessage(message);\n const isPinned = isPinnedFlag;\n\n const canEdit = !isSystem && !isSignal && isOwnMessage;\n\n // Delete for everyone:\n // + Team channel: only the owner can perform this action natively.\n // + Messaging channel: only own messages can be deleted\n const canDeleteForEveryoneTeam = isTeam && isOwner;\n const canDeleteForEveryoneMessaging = !isTeam && isOwnMessage;\n\n const canDelete = !isSystem && (canDeleteForEveryoneTeam || canDeleteForEveryoneMessaging);\n const canDeleteForMe = !isSystem;\n const canReply = !isSystem && !isSignal;\n const canQuote = !isSystem && !isSignal;\n const canForward = !isSystem && !isSignal;\n const canPin = !isSystem && !isSignal;\n const canCopy = !isSystem && !isSignal && Boolean(message.text?.trim());\n\n const hasCapEdit = hasCapability('update-own-message');\n const hasCapDelete = !isTeam || isOwner || (isOwnMessage && hasCapability('delete-own-message'));\n // Apply the delete-own-message capability to the \"delete for me\" action for own messages\n const hasCapDeleteForMe = !isTeam || isOwner || !isOwnMessage || hasCapability('delete-own-message');\n\n const hasCapReply = hasCapability('send-reply');\n const hasCapQuote = hasCapability('quote-message');\n const hasCapPin = hasCapability('pin-message');\n\n return {\n canEdit,\n canDelete,\n canDeleteForMe,\n canReply,\n canQuote,\n canForward,\n canPin,\n canCopy,\n isPinned,\n hasCapEdit,\n hasCapDelete,\n hasCapDeleteForMe,\n hasCapPin,\n hasCapReply,\n hasCapQuote,\n };\n }, [activeChannel, isTeam, isOwner, hasCapability, messageType, message.text, isPinnedFlag, isOwnMessage]); // Use capabilities from hook\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { isGroupChannel } from '../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../channelRoleUtils';\n\nexport const useChannelCapabilities = () => {\n const { activeChannel, client } = useChatClient();\n const [updateTick, setUpdateTick] = useState(0);\n\n // Real-time synchronization for channel adjustments\n useEffect(() => {\n if (!activeChannel) return;\n const handleUpdate = () => setUpdateTick(t => t + 1);\n \n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const currentUserId = client?.userID || '';\n const isGroupCh = isGroupChannel(activeChannel);\n const role = (activeChannel?.state as any)?.members?.[currentUserId]?.channel_role;\n \n const isOwner = role === CHANNEL_ROLES.OWNER || activeChannel?.data?.created_by_id === currentUserId;\n const isModerator = role === CHANNEL_ROLES.MODERATOR;\n const isOwnerOrModerator = isOwner || isModerator || canManageChannel(role);\n\n const capabilities: string[] = isGroupCh ? (activeChannel?.data as any)?.member_capabilities || [] : [];\n\n const hasCapability = useCallback((cap: string) => {\n return !isGroupCh || isOwnerOrModerator || capabilities.includes(cap);\n }, [isGroupCh, isOwnerOrModerator, capabilities, updateTick]); // React to updateTick correctly\n\n return {\n isGroupChannel: isGroupCh,\n isOwner,\n isModerator,\n isOwnerOrModerator,\n hasCapability,\n role,\n capabilities\n };\n};\n","export const MESSAGE_TYPES = {\n REGULAR: 'regular',\n SYSTEM: 'system',\n STICKER: 'sticker',\n SIGNAL: 'signal',\n ERROR: 'error',\n} as const;\n\nexport const ATTACHMENT_TYPES = {\n IMAGE: 'image',\n VIDEO: 'video',\n VOICE_RECORDING: 'voiceRecording',\n LINK_PREVIEW: 'linkPreview',\n FILE: 'file',\n AUDIO: 'audio',\n} as const;\n\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES] | string;\nexport type AttachmentType = (typeof ATTACHMENT_TYPES)[keyof typeof ATTACHMENT_TYPES] | string;\n\n// Helpers cho message\nexport function isSystemMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.SYSTEM;\n}\n\nexport function isStickerMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.STICKER;\n}\n\nexport function isRegularMessage(message: any): boolean {\n return !message?.type || message?.type === MESSAGE_TYPES.REGULAR;\n}\n\nexport function isSignalMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.SIGNAL;\n}\n\n// Helpers cho attachment\nexport function isImageAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.IMAGE;\n}\n\nexport function isVideoAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.VIDEO;\n}\n\nexport function isVoiceRecordingAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.VOICE_RECORDING;\n}\n\nexport function isLinkPreviewAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.LINK_PREVIEW;\n}\n\nexport function isImage(attachment: any): boolean {\n return Boolean(\n isImageAttachment(attachment) ||\n (!attachment?.type && (attachment?.mime_type?.startsWith('image/') || attachment?.image_url)),\n );\n}\n\nexport function isVideo(attachment: any): boolean {\n return !!(isVideoAttachment(attachment) || (!attachment.type && attachment.mime_type?.startsWith('video/')));\n}\n","import React from 'react';\nimport type { MessageReactionsProps } from '../types';\n\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst defaultReactionEmojiMap: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageReactions: React.FC<MessageReactionsProps> = React.memo(({\n reactionCounts,\n ownReactions,\n latestReactions,\n onClickReaction,\n disabled,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n if (!reactionCounts || Object.keys(reactionCounts).length === 0) return null;\n\n return (\n <div className={`ermis-message-reactions${disabled ? ' ermis-message-reactions--disabled' : ''}`}>\n {Object.entries(reactionCounts).map(([type, count]) => {\n const isOwn = \n ownReactions?.some((r) => r.type === type) ||\n latestReactions?.some((r) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n \n // Find users who reacted with this type for the tooltip\n const rawUserNames = latestReactions\n ?.filter((r) => r.type === type)\n .map((r: any) => r.user?.name || r.user?.id || r.user_id || 'Someone');\n \n const userNames = Array.from(new Set(rawUserNames || []))\n .map((n: any) => typeof n === 'string' ? n.replace(/‎|\\u200E/gi, '').trim() : n)\n .filter(Boolean);\n\n const tooltip = userNames.length > 0 ? userNames.join(', ') : type;\n const emoji = defaultReactionEmojiMap[type] || type;\n\n return (\n <button\n key={type}\n className={`ermis-message-reactions__item ${\n isOwn ? 'ermis-message-reactions__item--active' : ''\n }`}\n data-tooltip={tooltip}\n onClick={() => onClickReaction?.(type)}\n type=\"button\"\n >\n <span className=\"ermis-message-reactions__emoji\">{emoji}</span>\n <span className=\"ermis-message-reactions__count\">{count}</span>\n </button>\n );\n })}\n </div>\n );\n});\n\nMessageReactions.displayName = 'MessageReactions';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst QUICK_REACTIONS = ['like', 'love', 'haha', 'sad', 'fire'];\nconst EMOJI_MAP: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageQuickReactions: React.FC<{\n message: FormatMessageResponse;\n isOwnMessage: boolean;\n disabled?: boolean;\n}> = React.memo(({ message, isOwnMessage, disabled }) => {\n const { activeChannel, client } = useChatClient();\n const currentUserId = client?.userID;\n\n const handleReactionToggle = useCallback(\n async (type: string) => {\n if (!activeChannel) return;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n },\n [activeChannel, message, currentUserId]\n );\n\n return (\n <div className={`ermis-message-quick-reactions ${isOwnMessage ? 'ermis-message-quick-reactions--own' : ''} ${disabled ? 'ermis-message-quick-reactions--disabled' : ''}`}>\n {QUICK_REACTIONS.map((type) => {\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n return (\n <button\n key={type}\n className={`ermis-message-quick-reactions__btn ${\n isOwn ? 'ermis-message-quick-reactions__btn--active' : ''\n }`}\n title={type}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n handleReactionToggle(type);\n }}\n >\n {EMOJI_MAP[type]}\n </button>\n );\n })}\n </div>\n );\n});\n\nMessageQuickReactions.displayName = 'MessageQuickReactions';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { preloadImage, isImagePreloaded } from '../utils';\nimport type { FormatMessageResponse, Attachment, MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage, CallType } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { buildUserMap } from '../utils';\nimport { MediaLightbox } from './MediaLightbox';\nimport { getFileIcon } from './ChannelInfo/utils';\nimport type { AttachmentProps, MessageRendererProps, MessageBubbleProps, MediaLightboxItem } from '../types';\n\nexport type { AttachmentProps, MessageRendererProps, MessageBubbleProps } from '../types';\nimport {\n isVoiceRecordingAttachment,\n isLinkPreviewAttachment,\n isImage,\n isVideo\n} from '../messageTypeUtils';\n\n/* ----------------------------------------------------------\n Attachment renderers\n ---------------------------------------------------------- */\nconst ImageAttachment: React.FC<AttachmentProps> = React.memo(({ attachment, onClick }) => {\n const src = attachment.image_url || attachment.thumb_url || attachment.url;\n const thumbSrc = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => { preloadImage(src); }, [src]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const clickable = Boolean(onClick);\n\n return (\n <div\n className={`ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3${clickable ? ' ermis-attachment--clickable' : ''}`}\n onClick={onClick}\n role={clickable ? 'button' : undefined}\n tabIndex={clickable ? 0 : undefined}\n >\n {/* Blur placeholder: use thumb if available, otherwise shimmer */}\n {!loaded && (\n thumbSrc && thumbSrc !== src ? (\n <img\n className=\"ermis-attachment-blur-preview\"\n src={thumbSrc}\n alt=\"\"\n aria-hidden\n />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n alt={attachment.file_name || attachment.title || 'image'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n {clickable && (\n <div className=\"ermis-attachment__overlay\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </div>\n )}\n </div>\n );\n}, (prev, next) => {\n const prevSrc = prev.attachment.image_url || prev.attachment.thumb_url || prev.attachment.url;\n const nextSrc = next.attachment.image_url || next.attachment.thumb_url || next.attachment.url;\n return prevSrc === nextSrc && prev.onClick === next.onClick;\n});\n(ImageAttachment as any).displayName = 'ImageAttachment';\n\nconst VideoAttachment: React.FC<AttachmentProps> = React.memo(({ attachment, onClick }) => {\n const src = attachment.asset_url || attachment.url;\n const posterSrc = attachment.image_url || attachment.thumb_url;\n const blurThumb = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = posterSrc ? isImagePreloaded(posterSrc) : true;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (posterSrc) preloadImage(posterSrc);\n }, [posterSrc]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, posterSrc]);\n\n const clickable = Boolean(onClick);\n\n // When clickable (lightbox mode): show poster thumbnail + play icon overlay\n if (clickable) {\n return (\n <div\n className=\"ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3 ermis-attachment--clickable\"\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n >\n {!loaded && (\n blurThumb && blurThumb !== posterSrc ? (\n <img className=\"ermis-attachment-blur-preview\" src={blurThumb} alt=\"\" aria-hidden />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n {posterSrc ? (\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--video-poster${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={posterSrc}\n alt={attachment.file_name || 'video'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n ) : (\n <video\n className={`ermis-attachment ermis-attachment--video${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n />\n )}\n <div className=\"ermis-attachment__overlay\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n );\n }\n\n // Default inline video player (no lightbox)\n return (\n <div className=\"ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3\">\n {!loaded && (\n blurThumb && blurThumb !== posterSrc ? (\n <img\n className=\"ermis-attachment-blur-preview\"\n src={blurThumb}\n alt=\"\"\n aria-hidden\n />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n {posterSrc && !loaded && (\n <img\n ref={imgRef}\n src={posterSrc}\n className=\"ermis-attachment--hidden-loader\"\n onLoad={() => setLoaded(true)}\n alt=\"poster-loader\"\n />\n )}\n <video\n className={`ermis-attachment ermis-attachment--video${loaded || !posterSrc ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n poster={posterSrc}\n controls\n preload=\"metadata\"\n onLoadedData={() => {\n if (!posterSrc) setLoaded(true);\n }}\n />\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.asset_url || prev.attachment.url) ===\n (next.attachment.asset_url || next.attachment.url) && prev.onClick === next.onClick;\n});\n(VideoAttachment as any).displayName = 'VideoAttachment';\n\nconst FileAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const url = attachment.url || attachment.asset_url;\n const name = attachment.file_name || attachment.title || 'File';\n const size = attachment.file_size;\n const mimeType = attachment.mime_type || attachment.type || '';\n const ext = name.split('.').pop()?.toUpperCase() || 'FILE';\n const { client } = useChatClient();\n\n const handleDownload = useCallback(async (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!url) return;\n\n try {\n const blob = await client.downloadMedia(url);\n const urlBlob = window.URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = urlBlob;\n a.download = name;\n document.body.appendChild(a);\n a.click();\n a.remove();\n window.URL.revokeObjectURL(urlBlob);\n } catch {\n window.open(url, '_blank', 'noopener,noreferrer');\n }\n }, [client, url, name]);\n\n return (\n <div className=\"ermis-attachment ermis-attachment--file\">\n <span className=\"ermis-attachment__file-icon\">\n {getFileIcon(mimeType, name)}\n <span className=\"ermis-attachment__file-ext\">{ext}</span>\n </span>\n <span className=\"ermis-attachment__file-info\">\n <span className=\"ermis-attachment__file-name\">{name}</span>\n {size && (\n <span className=\"ermis-attachment__file-size\">\n {typeof size === 'number' ? `${(size / 1024).toFixed(1)} KB` : size}\n </span>\n )}\n </span>\n <button\n className=\"ermis-attachment__file-download\"\n onClick={handleDownload}\n title=\"Download\"\n type=\"button\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.url || prev.attachment.asset_url) ===\n (next.attachment.url || next.attachment.asset_url);\n});\n(FileAttachment as any).displayName = 'FileAttachment';\n\nconst VoiceRecordingAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const src = attachment.asset_url || attachment.url;\n if (!src) return null;\n\n const durationSec = attachment.duration ?? 0;\n const mins = Math.floor(durationSec / 60);\n const secs = Math.round(durationSec % 60);\n const durationLabel = `${mins}:${secs.toString().padStart(2, '0')}`;\n\n return (\n <div className=\"ermis-attachment ermis-attachment--voice\">\n <span className=\"ermis-attachment__voice-icon\">🎙️</span>\n <audio src={src} controls preload=\"metadata\" className=\"ermis-attachment__voice-player\" />\n <span className=\"ermis-attachment__voice-duration\">{durationLabel}</span>\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.asset_url || prev.attachment.url) ===\n (next.attachment.asset_url || next.attachment.url);\n});\n(VoiceRecordingAttachment as any).displayName = 'VoiceRecordingAttachment';\n\nconst LinkPreviewAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const url = attachment.link_url || attachment.og_scrape_url || attachment.title_link || attachment.url;\n const title = attachment.title;\n const description = attachment.text;\n const image = attachment.image_url;\n\n const alreadyCached = image ? isImagePreloaded(image) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (image) preloadImage(image);\n }, [image]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, image]);\n\n if (!title) return null;\n\n return (\n <a\n className=\"ermis-attachment ermis-attachment--link-preview\"\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {image && (\n <div className=\"ermis-attachment__link-image-wrapper\">\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-attachment__link-image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={image}\n alt={title || 'preview'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n )}\n <div className=\"ermis-attachment__link-info\">\n {title && <span className=\"ermis-attachment__link-title\">{title}</span>}\n {description && <span className=\"ermis-attachment__link-description\">{description}</span>}\n {url && (\n <span className=\"ermis-attachment__link-url\">\n {new URL(url).hostname}\n </span>\n )}\n </div>\n </a>\n );\n}, (prev, next) => {\n return (prev.attachment.link_url || prev.attachment.og_scrape_url || prev.attachment.url) ===\n (next.attachment.link_url || next.attachment.og_scrape_url || next.attachment.url);\n});\n(LinkPreviewAttachment as any).displayName = 'LinkPreviewAttachment';\n\nexport const MessageAttachment: React.FC<AttachmentProps> = ({ attachment }) => {\n if (isImage(attachment)) return <ImageAttachment attachment={attachment} />;\n if (isVideo(attachment)) return <VideoAttachment attachment={attachment} />;\n if (isVoiceRecordingAttachment(attachment)) return <VoiceRecordingAttachment attachment={attachment} />;\n if (isLinkPreviewAttachment(attachment)) return <LinkPreviewAttachment attachment={attachment} />;\n return <FileAttachment attachment={attachment} />;\n};\n\nexport const AttachmentList: React.FC<{ attachments?: Attachment[] }> = React.memo(({ attachments }) => {\n if (!attachments || attachments.length === 0) return null;\n\n // Group by type\n const media = attachments.filter((a) => isImage(a) || isVideo(a));\n const files = attachments.filter((a) => !isImage(a) && !isVideo(a) && !isVoiceRecordingAttachment(a) && !isLinkPreviewAttachment(a));\n const voices = attachments.filter(isVoiceRecordingAttachment);\n const links = attachments.filter(isLinkPreviewAttachment);\n\n // Lightbox state\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [lightboxIndex, setLightboxIndex] = useState(0);\n\n // Build lightbox items from media attachments\n const lightboxItems = useMemo<MediaLightboxItem[]>(() => {\n return media.map(att => {\n if (isImage(att)) {\n return {\n type: 'image' as const,\n src: att.image_url || att.thumb_url || att.url || '',\n alt: att.file_name || att.title,\n };\n }\n return {\n type: 'video' as const,\n src: att.asset_url || att.url || '',\n alt: att.file_name || att.title,\n posterSrc: att.image_url || att.thumb_url,\n };\n });\n }, [media]);\n\n const openLightbox = useCallback((index: number) => {\n setLightboxIndex(index);\n setLightboxOpen(true);\n }, []);\n\n const closeLightbox = useCallback(() => {\n setLightboxOpen(false);\n }, []);\n\n const mediaGridClass = media.length === 1\n ? 'ermis-attachment-grid ermis-attachment-grid--single'\n : 'ermis-attachment-grid ermis-attachment-grid--multi';\n\n return (\n <div className=\"ermis-attachment-list\">\n {/* Media group: images + videos in grid */}\n {media.length > 0 && (\n <div className={mediaGridClass}>\n {media.map((att, i) => (\n isImage(att)\n ? <ImageAttachment key={att.id || `img-${i}`} attachment={att} onClick={() => openLightbox(i)} />\n : <VideoAttachment key={att.id || `vid-${i}`} attachment={att} onClick={() => openLightbox(i)} />\n ))}\n </div>\n )}\n {/* File group */}\n {files.map((att, i) => (\n <FileAttachment key={att.id || `file-${i}`} attachment={att} />\n ))}\n {/* Voice recording group */}\n {voices.map((att, i) => (\n <VoiceRecordingAttachment key={att.id || `voice-${i}`} attachment={att} />\n ))}\n {/* Link preview group */}\n {links.map((att, i) => (\n <LinkPreviewAttachment key={att.id || `link-${i}`} attachment={att} />\n ))}\n\n {/* Media Lightbox */}\n {lightboxItems.length > 0 && (\n <MediaLightbox\n items={lightboxItems}\n initialIndex={lightboxIndex}\n isOpen={lightboxOpen}\n onClose={closeLightbox}\n />\n )}\n </div>\n );\n}, (prev, next) => {\n // Skip re-render if same attachment array reference\n if (prev.attachments === next.attachments) return true;\n if (!prev.attachments || !next.attachments) return false;\n if (prev.attachments.length !== next.attachments.length) return false;\n return prev.attachments.every((a, i) => a.id === next.attachments![i].id);\n});\n(AttachmentList as any).displayName = 'AttachmentList';\n\n/* ----------------------------------------------------------\n Message renderers by MessageLabel type\n ---------------------------------------------------------- */\n\n/**\n * Detect URLs and emails in plain text, wrapping them in <a> tags.\n * Returns an array of React nodes (strings and link elements).\n */\nconst URL_REGEX = /(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+|[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,})/g;\n\nfunction linkifyText(text: string, keyPrefix: string): React.ReactNode[] {\n const parts = text.split(URL_REGEX);\n if (parts.length === 1) return [text];\n\n return parts.map((part, i) => {\n if (URL_REGEX.test(part)) {\n // Reset lastIndex since we reuse the regex\n URL_REGEX.lastIndex = 0;\n const isEmail = part.includes('@') && !part.startsWith('http');\n const href = isEmail ? `mailto:${part}` : (part.startsWith('http') ? part : `https://${part}`);\n return (\n <a\n key={`${keyPrefix}-link-${i}`}\n className=\"ermis-text-link\"\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {part}\n </a>\n );\n }\n // Reset lastIndex\n URL_REGEX.lastIndex = 0;\n return part;\n });\n}\n\n/**\n * Parse message text: render @mentions as highlighted spans,\n * and auto-detect URLs/emails in non-mention text parts.\n */\nfunction renderTextWithMentions(\n text: string,\n message: FormatMessageResponse,\n userMap: Record<string, string>,\n): React.ReactNode {\n const mentionedUsers: string[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, just linkify the text\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return linkifyText(text, 'txt');\n }\n\n // Build a list of patterns to replace: @userId → @userName\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userId of mentionedUsers) {\n replacements.push({\n pattern: `@${userId}`,\n label: `@${userMap[userId] ?? userId}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({ pattern: '@all', label: '@all' });\n }\n\n // Build a regex that matches any of the mention patterns\n const escaped = replacements.map((r) =>\n r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n );\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n const parts = text.split(regex);\n\n // Map from pattern → label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return parts.flatMap((part, i) => {\n const label = patternToLabel.get(part);\n if (label) {\n // Mention — render as span, do NOT linkify\n return (\n <span key={`mention-${i}`} className=\"ermis-mention\">\n {label}\n </span>\n );\n }\n // Non-mention text — linkify URLs/emails\n return linkifyText(part, `p${i}`);\n });\n}\n\n/** Regular message: text with @mentions + attachments */\nexport const RegularMessage: React.FC<MessageRendererProps> = React.memo(({ message }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const textContent = message.text\n ? renderTextWithMentions(message.text, message, userMap)\n : null;\n\n const attachmentsToRender = useMemo(() => {\n if (!message.attachments || message.attachments.length === 0) return [];\n\n const text = (message.text || '').trim();\n const URL_REGEX_STRICT = /^(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+)$/;\n const isOnlyUrl = URL_REGEX_STRICT.test(text);\n\n return message.attachments.filter(att => {\n if (isLinkPreviewAttachment(att)) return isOnlyUrl;\n return true;\n });\n }, [message.attachments, message.text]);\n\n const hasAttachments = attachmentsToRender.length > 0;\n\n if (hasAttachments) {\n return (\n <div className=\"ermis-message-content--with-attachments\">\n {textContent && (\n <span className=\"ermis-message-list__item-text\">{textContent}</span>\n )}\n <AttachmentList attachments={attachmentsToRender} />\n </div>\n );\n }\n\n return (\n <>\n {textContent && (\n <span className=\"ermis-message-list__item-text\">{textContent}</span>\n )}\n </>\n );\n}, (prev, next) => {\n return prev.message.id === next.message.id &&\n prev.message.updated_at === next.message.updated_at &&\n prev.message.text === next.message.text &&\n prev.isOwnMessage === next.isOwnMessage;\n});\nRegularMessage.displayName = 'RegularMessage';\n\n/** System message: centered info text, parsed from raw format */\nexport const SystemMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const parsedText = useMemo(\n () => (message.text ? parseSystemMessage(message.text, userMap) : ''),\n [message.text, userMap],\n );\n\n return (\n <span className=\"ermis-message-list__system-text\">\n {parsedText || message.text}\n </span>\n );\n};\n\n/** Signal message: call events */\nexport const SignalMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const { client } = useChatClient();\n\n const rawText = message.text ?? '';\n const result = rawText ? parseSignalMessage(rawText, client.userID || '') : null;\n\n if (!result) {\n return (\n <span className=\"ermis-message-list__signal-text\">\n {rawText}\n </span>\n );\n }\n\n const isSuccess = !!result.duration;\n const colorModifier = isSuccess ? 'success' : 'missed';\n const isAudio = result.callType === CallType.AUDIO;\n\n return (\n <div className=\"ermis-signal-message\">\n <div className={`ermis-signal-message__icon ermis-signal-message__icon--${colorModifier}`}>\n {isAudio ? (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" />\n </svg>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\" />\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-signal-message__body\">\n <span className={`ermis-signal-message__text ermis-signal-message__text--${colorModifier}`}>\n {result.text}\n </span>\n {result.duration && (\n <span className=\"ermis-signal-message__duration\">{result.duration}</span>\n )}\n </div>\n </div>\n );\n};\n\n/** Poll message */\nexport const PollMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <div className=\"ermis-message-poll\">\n <span className=\"ermis-message-poll__icon\">📊</span>\n <span className=\"ermis-message-poll__text\">{message.text || 'Poll'}</span>\n </div>\n);\n\n/** Sticker message */\nexport const StickerMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const stickerUrl = (message as any).sticker_url;\n\n const alreadyCached = stickerUrl ? isImagePreloaded(stickerUrl) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (stickerUrl) preloadImage(stickerUrl);\n }, [stickerUrl]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, stickerUrl]);\n\n if (stickerUrl) {\n return (\n <div className=\"ermis-message-sticker-wrapper\">\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-message-sticker${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={stickerUrl}\n alt=\"sticker\"\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n );\n }\n return <span className=\"ermis-message-list__item-text\">{message.text}</span>;\n};\n\n/** Error message */\nexport const ErrorMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <span className=\"ermis-message-error\">{message.text || 'Message failed'}</span>\n);\n\n/**\n * Map from MessageLabel → component.\n * Consumer can override individual renderers via the `messageRenderers` prop.\n */\nexport const defaultMessageRenderers: Record<\n MessageLabel,\n React.ComponentType<MessageRendererProps>\n> = {\n regular: RegularMessage,\n system: SystemMessage,\n signal: SignalMessage,\n poll: PollMessage,\n sticker: StickerMessage,\n error: ErrorMessage,\n};\n","import React from 'react';\nimport type { MediaTab } from '../../types';\n\nexport function getFileIcon(contentType: string, fileName: string): React.ReactNode {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n\n if (contentType.includes('pdf') || ext === 'pdf') {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n );\n }\n\n if (contentType.includes('zip') || contentType.includes('rar') || contentType.includes('archive') || ['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 8v13H3V3h13\" />\n <path d=\"M16 3v5h5\" />\n <path d=\"M10 12h4M10 16h4M10 8h1\" />\n </svg>\n );\n }\n\n // Default file icon\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n );\n}\n\nexport const ROLE_WEIGHTS: Record<string, number> = {\n owner: 4,\n moder: 3,\n member: 2,\n pending: 1,\n};\n\nexport const MESSAGING_TABS: MediaTab[] = ['media', 'links', 'files'];\nexport const ALL_TABS: MediaTab[] = ['members', 'media', 'links', 'files'];\n\nexport const PENDING_STYLE = { opacity: 0.7, transition: 'opacity 0.15s ease' } as const;\nexport const READY_STYLE = { opacity: 1, transition: 'opacity 0.15s ease' } as const;\n","import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { PinnedMessageItemProps, PinnedMessagesProps } from '../types';\n\n/* ----------------------------------------------------------\n Default PinnedMessageItem\n ---------------------------------------------------------- */\nconst DefaultPinnedMessageItem: React.FC<PinnedMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n onClickMessage,\n onUnpin,\n AvatarComponent,\n}) => {\n const { activeChannel } = useChatClient();\n const userName = message.user?.name || message.user_id || 'Unknown';\n const userAvatar = message.user?.avatar;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n let previewText = message.text || '';\n const isSticker = isStickerMessage(message);\n\n if (!previewText && hasAttachments) {\n const firstAttach = message.attachments![0];\n previewText = firstAttach.title || `${firstAttach.type || 'file'}`;\n } else if (isSticker) {\n previewText = 'Sticker';\n }\n\n // Convert @userId → @UserName in preview text\n if (previewText) {\n previewText = replaceMentionsForPreview(previewText, message, userMap);\n }\n\n // Attachment icon prefix\n let attachIcon = '';\n if (hasAttachments) {\n const type = message.attachments![0].type;\n if (type === 'image') attachIcon = '📷 ';\n else if (type === 'video') attachIcon = '🎥 ';\n else if (type === 'audio') attachIcon = '🎵 ';\n else attachIcon = '📄 ';\n } else if (isSticker) {\n attachIcon = '😀 ';\n }\n\n return (\n <div\n className={`ermis-pinned-messages__item ${isOwnMessage ? 'ermis-pinned-messages__item--own' : ''}`}\n onClick={() => onClickMessage?.(message.id)}\n role=\"button\"\n tabIndex={0}\n >\n <AvatarComponent image={userAvatar} name={userName} size={28} />\n <div className=\"ermis-pinned-messages__item-content\">\n <span className=\"ermis-pinned-messages__item-user\">{userName}</span>\n <span className=\"ermis-pinned-messages__item-text\">{attachIcon}{previewText || 'Attachment'}</span>\n </div>\n <button\n className=\"ermis-pinned-messages__unpin-btn\"\n onClick={(e) => { e.stopPropagation(); onUnpin?.(message.id); }}\n title=\"Unpin message\"\n aria-label=\"Unpin message\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\" />\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </button>\n </div>\n );\n});\nDefaultPinnedMessageItem.displayName = 'DefaultPinnedMessageItem';\n\n/* ----------------------------------------------------------\n PinnedMessages component\n ---------------------------------------------------------- */\nexport const PinnedMessages: React.FC<PinnedMessagesProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n PinnedMessageItemComponent = DefaultPinnedMessageItem,\n onClickMessage,\n maxCollapsed = 1,\n}) => {\n const { activeChannel, client, messages } = useChatClient();\n const [expanded, setExpanded] = useState(false);\n const currentUserId = client.userID;\n\n // Reset expanded state when switching channels\n useEffect(() => {\n setExpanded(false);\n }, [activeChannel]);\n\n const pinnedMessages = useMemo<FormatMessageResponse[]>(() => {\n if (!activeChannel) return [];\n const pinned = (activeChannel.state as any)?.pinnedMessages;\n return Array.isArray(pinned) ? pinned : [];\n }, [activeChannel, messages]);\n\n const toggleExpanded = useCallback(() => {\n setExpanded((prev) => !prev);\n }, []);\n\n const handleUnpin = useCallback(async (messageId: string) => {\n if (!activeChannel) return;\n try {\n await activeChannel.unpinMessage(messageId);\n } catch (err) {\n console.error('Failed to unpin message', err);\n }\n }, [activeChannel]);\n\n if (pinnedMessages.length === 0) return null;\n\n const displayedMessages = expanded\n ? pinnedMessages\n : pinnedMessages.slice(0, maxCollapsed);\n\n const hasMore = pinnedMessages.length > maxCollapsed;\n\n return (\n <div className={`ermis-pinned-messages${expanded ? ' ermis-pinned-messages--expanded' : ''}${className ? ` ${className}` : ''}`}>\n {/* Header bar */}\n <div className=\"ermis-pinned-messages__header\" onClick={toggleExpanded}>\n <svg className=\"ermis-pinned-messages__icon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n <span className=\"ermis-pinned-messages__label\">\n {pinnedMessages.length} pinned message{pinnedMessages.length > 1 ? 's' : ''}\n </span>\n {hasMore && (\n <button\n className=\"ermis-pinned-messages__toggle\"\n onClick={(e) => { e.stopPropagation(); toggleExpanded(); }}\n >\n {expanded ? 'Collapse' : 'See all'}\n </button>\n )}\n </div>\n\n {/* Pinned message list */}\n <div className=\"ermis-pinned-messages__list\">\n {displayedMessages.map((msg) => (\n <PinnedMessageItemComponent\n key={msg.id}\n message={msg}\n isOwnMessage={msg.user_id === currentUserId || msg.user?.id === currentUserId}\n onClickMessage={onClickMessage}\n onUnpin={handleUnpin}\n AvatarComponent={AvatarComponent}\n />\n ))}\n </div>\n </div>\n );\n});\n\nPinnedMessages.displayName = 'PinnedMessages';\n","import React from 'react';\nimport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\nimport { Avatar } from './Avatar';\nimport { formatReadTimestamp } from '../utils';\n\nexport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\n\n/* ----------------------------------------------------------\n Default Tooltip — shown on hover\n ---------------------------------------------------------- */\nconst DefaultReadReceiptsTooltip: React.FC<ReadReceiptsTooltipProps> = React.memo(({\n readers,\n AvatarComponent,\n}) => (\n <div className=\"ermis-read-receipts__tooltip-wrapper\">\n <div className=\"ermis-read-receipts__tooltip\">\n {readers.map((reader) => (\n <div key={reader.id} className=\"ermis-read-receipts__tooltip-item\">\n <AvatarComponent\n image={reader.avatar}\n name={reader.name || reader.id}\n size={20}\n />\n <div className=\"ermis-read-receipts__tooltip-info\">\n <span className=\"ermis-read-receipts__tooltip-name\">{reader.name || reader.id}</span>\n <span className=\"ermis-read-receipts__tooltip-time\">{formatReadTimestamp(reader.last_read)}</span>\n </div>\n </div>\n ))}\n </div>\n </div>\n));\nDefaultReadReceiptsTooltip.displayName = 'DefaultReadReceiptsTooltip';\n\n/* ----------------------------------------------------------\n ReadReceipts — main component\n ---------------------------------------------------------- */\nexport const ReadReceipts: React.FC<ReadReceiptsProps> = React.memo(({\n readers,\n maxAvatars = 5,\n AvatarComponent = Avatar,\n TooltipComponent = DefaultReadReceiptsTooltip,\n showTooltip = true,\n}) => {\n // Only render when there are actual readers (avatar-based display)\n // Sent/Sending/Error status icons are now rendered inline inside the message bubble\n if (!readers || readers.length === 0) {\n return null;\n }\n\n const visible = readers.slice(0, maxAvatars);\n const overflow = readers.length - maxAvatars;\n\n return (\n <div className=\"ermis-read-receipts\">\n <div className=\"ermis-read-receipts__avatars\">\n {visible.map((reader) => (\n <AvatarComponent\n key={reader.id}\n image={reader.avatar}\n name={reader.name || reader.id}\n size={16}\n className=\"ermis-read-receipts__avatar\"\n />\n ))}\n {overflow > 0 && (\n <span className=\"ermis-read-receipts__overflow\">+{overflow}</span>\n )}\n {showTooltip && (\n <TooltipComponent\n readers={readers}\n AvatarComponent={AvatarComponent}\n />\n )}\n </div>\n </div>\n );\n});\n\nReadReceipts.displayName = 'ReadReceipts';\n","import React from 'react';\nimport { useTypingIndicator, type TypingUser } from '../hooks/useTypingIndicator';\n\nexport type TypingIndicatorProps = {\n /** Custom render function for the typing text */\n renderText?: (users: TypingUser[]) => React.ReactNode;\n};\n\n/**\n * Displays a \"X is typing...\" indicator below the message list.\n * Automatically subscribes to typing events via the useTypingIndicator hook.\n */\nexport const TypingIndicator: React.FC<TypingIndicatorProps> = React.memo(({ renderText }) => {\n const { typingUsers } = useTypingIndicator();\n\n const isActive = typingUsers.length > 0;\n\n const text = isActive\n ? (renderText ? renderText(typingUsers) : formatTypingText(typingUsers))\n : null;\n\n return (\n <div className={`ermis-typing-indicator${isActive ? ' ermis-typing-indicator--active' : ''}`}>\n {isActive && (\n <>\n <div className=\"ermis-typing-indicator__dots\">\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n </div>\n <span className=\"ermis-typing-indicator__text\">{text}</span>\n </>\n )}\n </div>\n );\n});\n\nTypingIndicator.displayName = 'TypingIndicator';\n\n/**\n * Format typing text based on number of users:\n * - 1 user: \"Alice is typing...\"\n * - 2 users: \"Alice and Bob are typing...\"\n * - 3+ users: \"Alice, Bob and 2 others are typing...\"\n */\nfunction formatTypingText(users: TypingUser[]): string {\n const names = users.map((u) => u.name || u.id);\n\n if (names.length === 1) {\n return `${names[0]} is typing...`;\n }\n if (names.length === 2) {\n return `${names[0]} and ${names[1]} are typing...`;\n }\n const remaining = names.length - 2;\n return `${names[0]}, ${names[1]} and ${remaining} other${remaining > 1 ? 's' : ''} are typing...`;\n}\n","import { useState, useEffect, useRef } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\nexport type TypingUser = {\n id: string;\n name?: string;\n};\n\n/**\n * Hook that subscribes to typing events on the active channel\n * and returns the list of currently‑typing users (excluding the current user).\n *\n * Stale entries are auto‑cleaned every 7 seconds, consistent with\n * the SDK's `channel.state.clean()` behaviour.\n */\nexport function useTypingIndicator() {\n const { activeChannel, client } = useChatClient();\n const [typingUsers, setTypingUsers] = useState<TypingUser[]>([]);\n const currentUserId = client.userID;\n\n // Keep a mutable map so event handlers can read/write without\n // creating stale‑closure issues.\n const typingMapRef = useRef<Map<string, { user: TypingUser; timestamp: number }>>(new Map());\n\n useEffect(() => {\n if (!activeChannel) {\n setTypingUsers([]);\n typingMapRef.current.clear();\n return;\n }\n\n // Reset when channel switches\n typingMapRef.current.clear();\n setTypingUsers([]);\n\n const syncState = () => {\n const users = Array.from(typingMapRef.current.values()).map((v) => v.user);\n setTypingUsers(users);\n };\n\n const handleTypingStart = (event: Event) => {\n const userId = event.user?.id;\n if (!userId || userId === currentUserId) return;\n\n typingMapRef.current.set(userId, {\n user: { id: userId, name: event.user?.name },\n timestamp: Date.now(),\n });\n syncState();\n };\n\n const handleTypingStop = (event: Event) => {\n const userId = event.user?.id;\n if (!userId) return;\n\n typingMapRef.current.delete(userId);\n syncState();\n };\n\n const sub1 = activeChannel.on('typing.start', handleTypingStart);\n const sub2 = activeChannel.on('typing.stop', handleTypingStop);\n\n // Auto‑clean stale entries every 7 seconds\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n let changed = false;\n for (const [uid, entry] of typingMapRef.current.entries()) {\n if (now - entry.timestamp > 7000) {\n typingMapRef.current.delete(uid);\n changed = true;\n }\n }\n if (changed) syncState();\n }, 3000);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n clearInterval(cleanupInterval);\n typingMapRef.current.clear();\n };\n }, [activeChannel, currentUserId]);\n\n return { typingUsers };\n}\n","import React from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type PendingOverlayProps = {\n channelImage?: string;\n channelName?: string;\n title: string;\n subtitle: string;\n acceptLabel: string;\n rejectLabel: string;\n onAccept: () => void;\n onReject: () => void;\n /** Label for the skip button (direct messaging channels) */\n skipLabel?: string;\n /** Handler for the skip action (direct messaging channels) */\n onSkip?: () => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n};\n\nexport const PendingOverlay: React.FC<PendingOverlayProps> = React.memo(({\n channelImage,\n channelName,\n title,\n subtitle,\n acceptLabel,\n rejectLabel,\n onAccept,\n onReject,\n skipLabel,\n onSkip,\n AvatarComponent,\n}) => (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <AvatarComponent image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{title}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{subtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n {onSkip ? (\n <button className=\"ermis-message-list__reject-btn\" onClick={onSkip}>{skipLabel || 'Skip'}</button>\n ) : (\n <button className=\"ermis-message-list__reject-btn\" onClick={onReject}>{rejectLabel}</button>\n )}\n <button className=\"ermis-message-list__accept-btn\" onClick={onAccept}>{acceptLabel}</button>\n </div>\n </div>\n </div>\n));\n\nPendingOverlay.displayName = 'PendingOverlay';\n","import React from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type SkippedOverlayProps = {\n channelImage?: string;\n channelName?: string;\n title: string;\n subtitle: string;\n acceptLabel: string;\n onAccept: () => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n};\n\nexport const SkippedOverlay: React.FC<SkippedOverlayProps> = React.memo(({\n channelImage,\n channelName,\n title,\n subtitle,\n acceptLabel,\n onAccept,\n AvatarComponent,\n}) => (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <AvatarComponent image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{title}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{subtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n <button className=\"ermis-message-list__accept-btn\" onClick={onAccept}>{acceptLabel}</button>\n </div>\n </div>\n </div>\n));\n\nSkippedOverlay.displayName = 'SkippedOverlay';\n","import React from 'react';\n\nexport type BannedOverlayProps = {\n isBlocked?: boolean;\n blockedTitle: string;\n bannedTitle: string;\n blockedSubtitle: string;\n bannedSubtitle: string;\n onUnblock?: () => void;\n};\n\nexport const BannedOverlay: React.FC<BannedOverlayProps> = React.memo(({\n isBlocked,\n blockedTitle,\n bannedTitle,\n blockedSubtitle,\n bannedSubtitle,\n onUnblock,\n}) => (\n <div className=\"ermis-message-list__banned-overlay\">\n <div className=\"ermis-message-list__banned-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__banned-overlay-title\">{isBlocked ? blockedTitle : bannedTitle}</span>\n <span className=\"ermis-message-list__banned-overlay-subtitle\">{isBlocked ? blockedSubtitle : bannedSubtitle}</span>\n {isBlocked && onUnblock && (\n <button\n className=\"ermis-message-list__unblock-btn\"\n onClick={onUnblock}\n >\n Unblock\n </button>\n )}\n </div>\n));\n\nBannedOverlay.displayName = 'BannedOverlay';\n","import React from 'react';\n\nexport type ClosedTopicOverlayProps = {\n title: string;\n subtitle: string;\n canManageTopic: boolean;\n reopenLabel: string;\n onReopen?: () => void;\n};\n\nexport const ClosedTopicOverlay: React.FC<ClosedTopicOverlayProps> = React.memo(({\n title,\n subtitle,\n canManageTopic,\n reopenLabel,\n onReopen,\n}) => (\n <div className=\"ermis-message-list__closed-overlay\">\n <div className=\"ermis-message-list__closed-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__closed-overlay-title\">{title}</span>\n <span className=\"ermis-message-list__closed-overlay-subtitle\">{subtitle}</span>\n {canManageTopic && onReopen && (\n <button\n className=\"ermis-message-list__reopen-btn\"\n onClick={onReopen}\n >\n {reopenLabel}\n </button>\n )}\n </div>\n));\n\nClosedTopicOverlay.displayName = 'ClosedTopicOverlay';\n","import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useMentions } from '../hooks/useMentions';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useEmojiPicker } from '../hooks/useEmojiPicker';\nimport { useMessageSend } from '../hooks/useMessageSend';\nimport { DefaultSendButton, DefaultAttachButton, DefaultEmojiButton } from './MessageInputDefaults';\nimport { MentionSuggestions } from './MentionSuggestions';\nimport { FilesPreview } from './FilesPreview';\nimport { ReplyPreview } from './ReplyPreview';\nimport { EditPreview } from './EditPreview';\nimport { buildUserMap, replaceMentionsForPreview, moveCaretToEnd } from '../utils';\nimport { getMentionHtml } from '../hooks/useMentions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { CHANNEL_ROLES } from '../channelRoleUtils';\nimport { isTopicChannel } from '../channelTypeUtils';\nimport type { MentionMember, MessageInputProps, FilePreviewItem } from '../types';\n\nexport type { MessageInputProps, SendButtonProps, AttachButtonProps, EmojiPickerProps, EmojiButtonProps } from '../types';\n\nexport const MessageInput: React.FC<MessageInputProps> = React.memo(({\n placeholder = 'Type a message...',\n onSend,\n className,\n SendButton = DefaultSendButton,\n AttachButton = DefaultAttachButton,\n FilesPreviewComponent = FilesPreview,\n MentionSuggestionsComponent = MentionSuggestions,\n disableAttachments = false,\n disableMentions = false,\n renderAbove,\n onBeforeSend,\n EmojiPickerComponent,\n EmojiButtonComponent = DefaultEmojiButton,\n ReplyPreviewComponent = ReplyPreview,\n EditPreviewComponent = EditPreview,\n bannedLabel = 'You have been banned from this channel',\n blockedLabel = 'You have blocked this user. Unblock to send messages.',\n linksDisabledLabel = 'Message blocked: Sending links is disabled for members.',\n keywordBlockedLabel = (match: string) => `Message blocked: Contains restricted word \"${match}\".`,\n sendDisabledLabel = 'Sending messages is disabled in this channel.',\n slowModeLabel = (cooldown: number) => (\n <>Slow mode is active. You can send another message in <strong>{cooldown}s</strong>.</>\n ),\n closedTopicLabel = 'This topic is closed.',\n}) => {\n const { client, activeChannel, syncMessages, quotedMessage, setQuotedMessage, editingMessage, setEditingMessage } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n const editableRef = React.useRef<HTMLDivElement>(null);\n const [hasContent, setHasContent] = useState(false);\n\n const { role, isGroupChannel: isTeamChannel, hasCapability } = useChannelCapabilities();\n const isTopic = isTopicChannel(activeChannel);\n const isClosedTopic = activeChannel?.data?.is_closed_topic === true;\n\n // Slow Mode Logic\n const [memberMessageCooldown, setMemberMessageCooldown] = useState(Number(activeChannel?.data?.member_message_cooldown) || 0);\n\n useEffect(() => {\n if (!activeChannel) return;\n setMemberMessageCooldown(Number(activeChannel.data?.member_message_cooldown) || 0);\n const handleUpdate = (event: Record<string, unknown>) => {\n const channelData = (event?.channel as Record<string, unknown>) || activeChannel.data;\n setMemberMessageCooldown(Number(channelData?.member_message_cooldown) || 0);\n };\n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const isSlowModeApplied = isTeamChannel && role === CHANNEL_ROLES.MEMBER && memberMessageCooldown > 0;\n\n const [cooldownEnd, setCooldownEnd] = useState<number | null>(null);\n const [cooldown, setCooldown] = useState(0);\n const lastMsgSentAtRef = useRef<number>(0);\n\n // Initialize cooldown state periodically or on change\n useEffect(() => {\n if (!isSlowModeApplied) {\n setCooldownEnd(null);\n setCooldown(0);\n return;\n }\n\n let lastMsgSentAt = lastMsgSentAtRef.current || 0;\n const messages = activeChannel?.state?.messages || [];\n\n // Iterate from newest to oldest to find actual highest timestamp\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].user?.id === client.userID) {\n const msgTime = new Date(messages[i].created_at).getTime();\n if (msgTime && !isNaN(msgTime) && msgTime > lastMsgSentAt) {\n lastMsgSentAt = msgTime;\n }\n break;\n }\n }\n\n if (lastMsgSentAt) {\n const cdEnd = lastMsgSentAt + memberMessageCooldown;\n if (cdEnd > Date.now()) {\n setCooldownEnd(cdEnd);\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n }, [isSlowModeApplied, activeChannel, memberMessageCooldown, client.userID]);\n\n // Tick the countdown visualization\n useEffect(() => {\n if (!cooldownEnd || cooldownEnd <= Date.now()) {\n setCooldown(0);\n return;\n }\n const updateCd = () => {\n const remaining = cooldownEnd - Date.now();\n if (remaining <= 0) {\n setCooldown(0);\n } else {\n setCooldown(Math.ceil(remaining / 1000));\n }\n };\n updateCd();\n const timer = setInterval(updateCd, 1000);\n return () => clearInterval(timer);\n }, [cooldownEnd]);\n\n const isSlowModeBlocked = isSlowModeApplied && cooldown > 0 && !editingMessage;\n\n const canSendMessage = hasCapability('send-message');\n const canSendLinks = hasCapability('send-links');\n\n const [keywordError, setKeywordError] = useState<string | null>(null);\n\n // Auto-clear link restriction banner if admin suddenly restores the capability\n useEffect(() => {\n if (keywordError?.includes('links') && canSendLinks) {\n setKeywordError(null);\n }\n }, [canSendLinks, keywordError]);\n\n const localOnBeforeSend = useCallback(async (text: string, attachments: FilePreviewItem[]) => {\n // Permission validation: Send Links\n if (!canSendLinks && text) {\n // Basic URL matching config\n const urlRegex = /(https?:\\/\\/[^\\s]+)|(www\\.[^\\s]+)|([a-zA-Z0-9-]+\\.[a-zA-Z]{2,}(\\/[^\\s]*)?)/i;\n if (urlRegex.test(text)) {\n setKeywordError(linksDisabledLabel);\n return false;\n }\n }\n\n // Custom Keyword validation\n const words = (activeChannel?.data?.filter_words as string[]) || [];\n if (words.length > 0 && text) {\n const lowerText = text.toLowerCase();\n const match = words.find(w => lowerText.includes(w.toLowerCase()));\n if (match) {\n setKeywordError(keywordBlockedLabel(match));\n // We could also visually shake the input box here\n return false;\n }\n }\n setKeywordError(null);\n if (onBeforeSend) {\n return await onBeforeSend(text, attachments);\n }\n return true;\n }, [activeChannel, onBeforeSend, canSendLinks]);\n\n const handleMessageSent = useCallback((text: string) => {\n if (isSlowModeApplied) {\n lastMsgSentAtRef.current = Date.now();\n setCooldownEnd(Date.now() + memberMessageCooldown);\n }\n onSend?.(text);\n }, [isSlowModeApplied, memberMessageCooldown, onSend]);\n\n // Auto-focus when channel changes or when reply/edit is selected\n useEffect(() => {\n if (activeChannel && editableRef.current) {\n editableRef.current.focus();\n }\n }, [activeChannel, quotedMessage, editingMessage]);\n\n\n /* ---------- Hooks ---------- */\n const {\n files, setFiles, fileInputRef,\n handleFilesSelected, handleRemoveFile, handleAttachClick, cleanupFiles,\n } = useFileUpload({ activeChannel, editableRef, setHasContent });\n\n // Pre-fill text and legacy attachments when editingMessage is set\n useEffect(() => {\n if (editingMessage && editableRef.current) {\n // 1. Prefill text content\n const rawText = editingMessage.text || '';\n\n // Extract user map locally since we have `activeChannel.state.members`\n const userMap = buildUserMap(activeChannel?.state);\n\n const htmlText = rawText\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\n/g, '<br>');\n\n editableRef.current.innerHTML = replaceMentionsForPreview(\n htmlText,\n editingMessage,\n userMap,\n getMentionHtml\n );\n\n // Move cursor to the end\n moveCaretToEnd(editableRef.current);\n\n // The API does not support attachment modifications during edits.\n // Flush any active files and only allow text/mention modifications.\n setFiles([]);\n setHasContent(!!editingMessage.text);\n }\n }, [editingMessage, setFiles]);\n\n // Cleanup blob URLs on unmount\n useEffect(() => {\n return () => cleanupFiles();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n } = useEmojiPicker({ editableRef, setHasContent });\n\n // Build member list from channel state (only for team channels and topics)\n const members = useMemo<MentionMember[]>(() => {\n if (!(isTeamChannel || isTopic)) return [];\n const list: MentionMember[] = [];\n const stateMembers = activeChannel?.state?.members as Record<string, unknown> | undefined;\n if (stateMembers && typeof stateMembers === 'object') {\n for (const [id, memberVal] of Object.entries(stateMembers)) {\n const member = memberVal as Record<string, any>;\n list.push({\n id,\n name: member?.user?.name || member?.user_id || id,\n avatar: member?.user?.avatar,\n });\n }\n }\n return list;\n }, [activeChannel, isTeamChannel, isTopic]);\n\n const {\n showSuggestions, filteredMembers, highlightIndex,\n handleInput: mentionHandleInput,\n handleKeyDown: mentionHandleKeyDown,\n selectMention, buildPayload, reset,\n } = useMentions({\n members,\n currentUserId: client.userID,\n editableRef,\n });\n\n const cancelEdit = useCallback(() => {\n setEditingMessage(null);\n cleanupFiles();\n setFiles([]);\n setHasContent(false);\n reset();\n if (editableRef.current) {\n editableRef.current.innerHTML = '';\n }\n }, [setEditingMessage, cleanupFiles, setFiles, setHasContent, reset]);\n\n const { sending, handleSend } = useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel: isTeamChannel || isTopic,\n buildPayload,\n reset,\n syncMessages,\n onSend: handleMessageSent,\n onBeforeSend: localOnBeforeSend,\n quotedMessage,\n clearQuotedMessage: () => setQuotedMessage(null),\n editingMessage,\n clearEditingMessage: () => setEditingMessage(null),\n });\n\n useEffect(() => {\n reset();\n handleEmojiClose();\n setFiles((prev) => {\n prev.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n return [];\n });\n setHasContent(false);\n\n // Stop typing indicator on channel switch / unmount\n return () => {\n activeChannel?.stopTyping();\n };\n }, [activeChannel, reset, handleEmojiClose, setFiles]);\n\n /* ---------- Input event handlers ---------- */\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n const content = el?.textContent?.trim() ?? '';\n setHasContent(content.length > 0 || files.length > 0);\n setKeywordError(null); // clear keyword error if user modifies input\n if ((isTeamChannel || isTopic) && !disableMentions) {\n mentionHandleInput();\n }\n // Send typing indicator (SDK throttles to 1 event per 2s)\n activeChannel?.keystroke();\n }, [isTeamChannel, isTopic, disableMentions, mentionHandleInput, files.length, activeChannel]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Prevent reacting to \"Enter\" when constructing characters with an IME (e.g. Vietnamese telex)\n if (e.nativeEvent.isComposing) return;\n\n if (e.key === 'Escape') {\n if (editingMessage) {\n cancelEdit();\n return;\n }\n if (quotedMessage) {\n setQuotedMessage(null);\n return;\n }\n }\n if ((isTeamChannel || isTopic) && !disableMentions) {\n const consumed = mentionHandleKeyDown(e);\n if (consumed) return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n if (!isSlowModeBlocked) {\n handleSend();\n }\n }\n },\n [isTeamChannel, isTopic, disableMentions, mentionHandleKeyDown, handleSend, editingMessage, quotedMessage, setEditingMessage, setQuotedMessage, reset],\n );\n\n const handlePaste = useCallback((e: React.ClipboardEvent) => {\n e.preventDefault();\n const plainText = e.clipboardData.getData('text/plain');\n document.execCommand('insertText', false, plainText);\n }, []);\n\n if (!activeChannel) return null;\n\n // Don't show input for pending invitations at all\n if (isPending) return null;\n\n // Show banned banner instead of input\n if (isBanned) {\n return (\n <div className={`ermis-message-input ermis-message-input--banned${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{bannedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show blocked banner instead of input (messaging channels only)\n if (isBlocked) {\n return (\n <div className={`ermis-message-input ermis-message-input--blocked${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__blocked-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{blockedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show closed topic banner instead of input\n if (isClosedTopic) {\n return (\n <div className={`ermis-message-input ermis-message-input--closed${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__closed-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n <span>{closedTopicLabel}</span>\n </div>\n </div>\n );\n }\n\n const isStillUploading = files.some((f) => f.status === 'uploading');\n\n return (\n <div className={`ermis-message-input${className ? ` ${className}` : ''}`}>\n {/* Reply preview */}\n {quotedMessage && !editingMessage && (\n <ReplyPreviewComponent\n message={quotedMessage}\n onDismiss={() => setQuotedMessage(null)}\n />\n )}\n\n {/* Edit preview */}\n {editingMessage && (\n <EditPreviewComponent\n message={editingMessage}\n onDismiss={cancelEdit}\n />\n )}\n\n {/* Custom content above input */}\n {renderAbove?.()}\n\n {/* File previews */}\n {!disableAttachments && <FilesPreviewComponent files={files} onRemove={handleRemoveFile} />}\n\n {/* Keyword Error Banner */}\n {keywordError && (\n <div className=\"ermis-message-input__keyword-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n {keywordError}\n </div>\n )}\n\n {/* Permission Disabled Banner */}\n {!canSendMessage && !editingMessage && (\n <div className=\"ermis-message-input__permission-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\n {sendDisabledLabel}\n </div>\n )}\n\n {/* Slow Mode Cooldown Banner */}\n {canSendMessage && isSlowModeBlocked && !keywordError && (\n <div className=\"ermis-message-input__slow-mode-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><polyline points=\"12 6 12 12 16 14\"></polyline></svg>\n {typeof slowModeLabel === 'function' ? slowModeLabel(cooldown) : slowModeLabel}\n </div>\n )}\n\n {/* Text input + send row */}\n <div className={`ermis-message-input__row${(!canSendMessage || isSlowModeBlocked || keywordError) ? ' ermis-message-input__row--banners-active' : ''}`}>\n <div className=\"ermis-message-input__editable-wrapper\">\n {canSendMessage && (isTeamChannel || isTopic) && !disableMentions && showSuggestions && (\n <MentionSuggestionsComponent\n members={filteredMembers}\n highlightIndex={highlightIndex}\n onSelect={selectMention}\n />\n )}\n\n {/* Attach button */}\n {!disableAttachments && (\n <AttachButton disabled={sending || !!editingMessage || isSlowModeBlocked || !canSendMessage} onClick={handleAttachClick} />\n )}\n\n {/* Hidden file input */}\n {!disableAttachments && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"ermis-message-input__file-input\"\n onChange={(e) => {\n handleFilesSelected(e.target.files);\n e.target.value = '';\n }}\n disabled={!!editingMessage || isSlowModeBlocked || !canSendMessage}\n />\n )}\n\n <div\n ref={editableRef}\n className=\"ermis-message-input__editable\"\n contentEditable={!sending && !isSlowModeBlocked && canSendMessage}\n role=\"textbox\"\n aria-placeholder={placeholder}\n data-placeholder={placeholder}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n suppressContentEditableWarning\n />\n\n {/* Emoji button — shown only when EmojiPickerComponent is provided */}\n {EmojiPickerComponent && (\n <EmojiButtonComponent active={emojiPickerOpen} onClick={isSlowModeBlocked ? () => { } : toggleEmojiPicker} />\n )}\n </div>\n <SendButton disabled={!hasContent || sending || isStillUploading || isSlowModeBlocked} onClick={handleSend} />\n </div>\n\n {/* Emoji picker — positioned above input */}\n {EmojiPickerComponent && emojiPickerOpen && (\n <div className=\"ermis-message-input__emoji-picker\">\n <EmojiPickerComponent onSelect={handleEmojiSelect} onClose={handleEmojiClose} />\n </div>\n )}\n </div>\n );\n});\n\nMessageInput.displayName = 'MessageInput';\n","import { useState, useCallback, useRef, useDeferredValue, useMemo } from 'react';\nimport { moveCaretAfterNode } from '../utils';\nimport type {\n MentionMember,\n MentionPayload,\n UseMentionsOptions,\n UseMentionsReturn,\n} from '../types';\n\nexport type { MentionMember, MentionPayload, UseMentionsOptions, UseMentionsReturn } from '../types';\n\nexport const MENTION_SPAN_CLASS = 'ermis-message-input__mention-span';\n\n/**\n * Returns the raw HTML string for a mention span, useful for initializing contenteditable divs.\n */\nexport function getMentionHtml(userId: string, displayName: string): string {\n const safeName = displayName.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n return `<span class=\"${MENTION_SPAN_CLASS}\" data-mention-id=\"${userId}\" contenteditable=\"false\">@${safeName}</span> `;\n}\n\n/**\n * Insert an atomic mention <span> at the current cursor position inside a\n * contenteditable element, followed by a trailing space.\n */\nfunction insertMentionAtCursor(\n editableEl: HTMLElement,\n userId: string,\n displayName: string,\n) {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n\n const { startContainer, startOffset } = range;\n if (startContainer.nodeType === Node.TEXT_NODE) {\n const textBefore = startContainer.textContent?.slice(0, startOffset) ?? '';\n const atIndex = textBefore.lastIndexOf('@');\n if (atIndex !== -1) {\n range.setStart(startContainer, atIndex);\n range.deleteContents();\n }\n }\n\n const span = document.createElement('span');\n span.className = MENTION_SPAN_CLASS;\n span.setAttribute('data-mention-id', userId);\n span.contentEditable = 'false';\n span.textContent = `@${displayName}`;\n\n range.insertNode(span);\n\n const space = document.createTextNode('\\u00A0');\n span.after(space);\n moveCaretAfterNode(space);\n\n editableEl.dispatchEvent(new Event('input', { bubbles: true }));\n}\n\n/**\n * Parse the DOM of a contenteditable div to produce a mention payload.\n */\nfunction buildPayloadFromDOM(editableEl: HTMLElement): MentionPayload {\n let text = '';\n let mentionedAll = false;\n const mentionedUsers: string[] = [];\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? '';\n return;\n }\n\n if (node instanceof HTMLElement) {\n const mentionId = node.getAttribute('data-mention-id');\n if (mentionId && node.classList.contains(MENTION_SPAN_CLASS)) {\n if (mentionId === '__all__') {\n mentionedAll = true;\n text += '@all';\n } else {\n if (!mentionedUsers.includes(mentionId)) {\n mentionedUsers.push(mentionId);\n }\n text += `@${mentionId}`;\n }\n return;\n }\n\n if (node.tagName === 'BR') {\n text += '\\n';\n return;\n }\n\n if (node.tagName === 'DIV' && text.length > 0 && !text.endsWith('\\n')) {\n text += '\\n';\n }\n }\n\n node.childNodes.forEach(walk);\n }\n\n walk(editableEl);\n text = text.replace(/\\u00A0/g, ' ').trim();\n\n return { text, mentioned_all: mentionedAll, mentioned_users: mentionedUsers };\n}\n\n/**\n * Scan the DOM for currently present mention spans and return their IDs.\n */\nfunction getActiveMentionIds(editableEl: HTMLElement): Set<string> {\n const ids = new Set<string>();\n const spans = editableEl.querySelectorAll(`.${MENTION_SPAN_CLASS}`);\n spans.forEach((span) => {\n const id = span.getAttribute('data-mention-id');\n if (id) ids.add(id);\n });\n return ids;\n}\n\nexport function useMentions({\n members,\n currentUserId,\n editableRef,\n}: UseMentionsOptions): UseMentionsReturn {\n const [showSuggestions, setShowSuggestions] = useState(false);\n const [query, setQuery] = useState('');\n const [highlightIndex, setHighlightIndex] = useState(0);\n const [activeMentionIds, setActiveMentionIds] = useState<Set<string>>(new Set());\n\n const deferredQuery = useDeferredValue(query);\n\n // All item: special entry\n const allItem: MentionMember = useMemo(\n () => ({ id: '__all__', name: 'all' }),\n [],\n );\n\n // Filter members based on deferred query, exclude self and already-mentioned\n const filteredMembers = useMemo(() => {\n const q = deferredQuery.toLowerCase();\n\n // Start with @all if not already selected\n const result: MentionMember[] = [];\n if (!activeMentionIds.has('__all__')) {\n if (!q || 'all'.includes(q)) {\n result.push(allItem);\n }\n }\n\n for (const m of members) {\n if (m.id === currentUserId) continue; // skip self\n if (activeMentionIds.has(m.id)) continue; // skip already mentioned\n if (q && !m.name.toLowerCase().includes(q)) continue; // filter by query\n result.push(m);\n }\n\n return result;\n }, [members, deferredQuery, activeMentionIds, currentUserId, allItem]);\n\n // Detect @ trigger from cursor position\n const detectTrigger = useCallback((): { triggered: boolean; query: string } => {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) {\n return { triggered: false, query: '' };\n }\n\n const { anchorNode, anchorOffset } = sel;\n if (!anchorNode || anchorNode.nodeType !== Node.TEXT_NODE) {\n return { triggered: false, query: '' };\n }\n\n const textBefore = anchorNode.textContent?.slice(0, anchorOffset) ?? '';\n\n // Find the last @ that is preceded by a space or is at the start\n const match = textBefore.match(/(^|[\\s\\u00A0])@(\\S*)$/);\n if (!match) {\n return { triggered: false, query: '' };\n }\n\n return { triggered: true, query: match[2] };\n }, []);\n\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n if (!el) return;\n\n // Update active mention IDs by scanning DOM\n setActiveMentionIds(getActiveMentionIds(el));\n\n // Detect @ trigger\n const result = detectTrigger();\n if (result.triggered) {\n setShowSuggestions(true);\n setQuery(result.query);\n setHighlightIndex(0);\n } else {\n setShowSuggestions(false);\n setQuery('');\n }\n }, [editableRef, detectTrigger]);\n\n const selectMention = useCallback(\n (member: MentionMember) => {\n const el = editableRef.current;\n if (!el) return;\n\n insertMentionAtCursor(el, member.id, member.name);\n\n // Update tracking\n setActiveMentionIds((prev) => new Set(prev).add(member.id));\n setShowSuggestions(false);\n setQuery('');\n\n // Re-focus the editable\n el.focus();\n },\n [editableRef],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent): boolean => {\n if (!showSuggestions || filteredMembers.length === 0) return false;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev < filteredMembers.length - 1 ? prev + 1 : 0,\n );\n return true;\n\n case 'ArrowUp':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev > 0 ? prev - 1 : filteredMembers.length - 1,\n );\n return true;\n\n case 'Enter':\n e.preventDefault();\n if (filteredMembers[highlightIndex]) {\n selectMention(filteredMembers[highlightIndex]);\n }\n return true;\n\n case 'Escape':\n e.preventDefault();\n setShowSuggestions(false);\n return true;\n\n default:\n return false;\n }\n },\n [showSuggestions, filteredMembers, highlightIndex, selectMention],\n );\n\n const buildPayload = useCallback((): MentionPayload => {\n const el = editableRef.current;\n if (!el) return { text: '', mentioned_all: false, mentioned_users: [] };\n return buildPayloadFromDOM(el);\n }, [editableRef]);\n\n const reset = useCallback(() => {\n setShowSuggestions(false);\n setQuery('');\n setHighlightIndex(0);\n setActiveMentionIds(new Set());\n const el = editableRef.current;\n if (el) {\n el.innerHTML = '';\n }\n }, [editableRef]);\n\n return {\n showSuggestions,\n filteredMembers,\n highlightIndex,\n handleInput,\n handleKeyDown,\n selectMention,\n buildPayload,\n reset,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { isHeicFile, isVideoFile, normalizeFileName } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nlet _fileIdCounter = 0;\nfunction nextFileId(): string {\n return `file-${Date.now()}-${++_fileIdCounter}`;\n}\n\nexport type UseFileUploadOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useFileUpload({ activeChannel, editableRef, setHasContent }: UseFileUploadOptions) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [files, setFiles] = useState<FilePreviewItem[]>([]);\n\n /**\n * Upload a single file immediately:\n * 1. Normalize file name\n * 2. Call sendFile API\n * 3. For video: generate + upload thumbnail\n * 4. Update file item state with uploaded URL\n */\n const uploadSingleFile = useCallback(async (item: FilePreviewItem) => {\n if (!activeChannel) return;\n\n try {\n const file = item.file!;\n const normalizedName = normalizeFileName(file.name);\n const fileToUpload = normalizedName !== file.name\n ? new File([file], normalizedName, { type: file.type, lastModified: file.lastModified })\n : file;\n\n const response = await activeChannel.sendFile(fileToUpload, fileToUpload.name, fileToUpload.type);\n const uploadedUrl = response.file;\n\n let thumbUrl = '';\n if (isVideoFile(file)) {\n try {\n const thumbBlob = await activeChannel.getThumbBlobVideo(file);\n if (thumbBlob) {\n const thumbFile = new File([thumbBlob], `thumb_${normalizedName}.jpg`, { type: 'image/jpeg' });\n const thumbResp = await activeChannel.sendFile(thumbFile, thumbFile.name, 'image/jpeg');\n thumbUrl = thumbResp.file;\n }\n } catch {\n // Thumbnail failure is non-critical\n }\n }\n\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'done' as const, uploadedUrl, thumbUrl, normalizedFile: fileToUpload }\n : f,\n ),\n );\n } catch (err: any) {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'error' as const, error: err?.message || 'Upload failed' }\n : f,\n ),\n );\n }\n }, [activeChannel]);\n\n const handleFilesSelected = useCallback((selectedFiles: FileList | null) => {\n if (!selectedFiles || selectedFiles.length === 0) return;\n\n const newItems: FilePreviewItem[] = Array.from(selectedFiles).map((file) => {\n const isPreviewable =\n (file.type.startsWith('image/') && !isHeicFile(file)) ||\n file.type.startsWith('video/');\n return {\n id: nextFileId(),\n file,\n previewUrl: isPreviewable ? URL.createObjectURL(file) : undefined,\n status: 'uploading' as const,\n };\n });\n\n setFiles((prev) => [...prev, ...newItems]);\n setHasContent(true);\n\n newItems.forEach((item) => uploadSingleFile(item));\n }, [uploadSingleFile, setHasContent]);\n\n const handleRemoveFile = useCallback((id: string) => {\n setFiles((prev) => {\n const item = prev.find((f) => f.id === id);\n if (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);\n const remaining = prev.filter((f) => f.id !== id);\n const el = editableRef.current;\n const textContent = el?.textContent?.trim() ?? '';\n if (remaining.length === 0 && textContent.length === 0) {\n setHasContent(false);\n }\n return remaining;\n });\n }, [editableRef, setHasContent]);\n\n const handleAttachClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Cleanup blob URLs\n const cleanupFiles = useCallback(() => {\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n }, [files]);\n\n return {\n files,\n setFiles,\n fileInputRef,\n handleFilesSelected,\n handleRemoveFile,\n handleAttachClick,\n cleanupFiles,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { moveCaretToEnd } from '../utils';\n\nexport type UseEmojiPickerOptions = {\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useEmojiPicker({ editableRef, setHasContent }: UseEmojiPickerOptions) {\n const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);\n const savedRangeRef = useRef<Range | null>(null);\n\n const handleEmojiSelect = useCallback((emoji: string) => {\n const el = editableRef.current;\n if (!el) return;\n\n // Restore saved cursor position, or move to end\n el.focus();\n const sel = window.getSelection();\n if (sel && savedRangeRef.current) {\n sel.removeAllRanges();\n sel.addRange(savedRangeRef.current);\n savedRangeRef.current = null;\n } else {\n moveCaretToEnd(el);\n }\n\n document.execCommand('insertText', false, emoji + ' ');\n setHasContent(true);\n setEmojiPickerOpen(false);\n }, [editableRef, setHasContent]);\n\n const handleEmojiClose = useCallback(() => {\n setEmojiPickerOpen(false);\n savedRangeRef.current = null;\n }, []);\n\n const toggleEmojiPicker = useCallback(() => {\n // Save current cursor position before picker steals focus\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0) {\n savedRangeRef.current = sel.getRangeAt(0).cloneRange();\n }\n setEmojiPickerOpen((prev) => !prev);\n }, []);\n\n return {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { buildAttachmentPayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nexport type UseMessageSendOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n files: FilePreviewItem[];\n setFiles: React.Dispatch<React.SetStateAction<FilePreviewItem[]>>;\n hasContent: boolean;\n setHasContent: (value: boolean) => void;\n isTeamChannel: boolean;\n buildPayload: () => { text: string; mentioned_all: boolean; mentioned_users: string[] };\n reset: () => void;\n syncMessages: () => void;\n onSend?: (text: string) => void;\n onBeforeSend?: (text: string, attachments: FilePreviewItem[]) => boolean | Promise<boolean>;\n /** Message being replied to */\n quotedMessage?: FormatMessageResponse | null;\n /** Clear quoted message after send */\n clearQuotedMessage?: () => void;\n /** Message being edited */\n editingMessage?: FormatMessageResponse | null;\n /** Clear edited message after send */\n clearEditingMessage?: () => void;\n};\n\nexport function useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel,\n buildPayload,\n reset,\n syncMessages,\n onSend,\n onBeforeSend,\n quotedMessage,\n clearQuotedMessage,\n editingMessage,\n clearEditingMessage,\n}: UseMessageSendOptions) {\n const [sending, setSending] = useState(false);\n const isProcessingRef = useRef(false);\n\n const handleSend = useCallback(async () => {\n if (!activeChannel || !hasContent || sending || isProcessingRef.current) return;\n\n // Wait for all files to finish uploading\n const stillUploading = files.some((f) => f.status === 'uploading');\n if (stillUploading) return;\n\n isProcessingRef.current = true;\n\n const payload = buildPayload();\n const text = payload.text.trim();\n const uploadedFiles = files.filter((f) => f.status === 'done');\n\n if (!text && uploadedFiles.length === 0) return;\n\n // onBeforeSend hook — return false to cancel\n if (onBeforeSend) {\n const proceed = await onBeforeSend(text, uploadedFiles);\n if (!proceed) {\n isProcessingRef.current = false;\n return;\n }\n }\n\n try {\n setSending(true);\n\n // Build attachment payloads from already-uploaded files (only applied on new messages)\n const attachments = uploadedFiles.map((f) => {\n if (f.originalAttachment) {\n return f.originalAttachment;\n }\n const fileObj = f.normalizedFile || f.file!;\n return buildAttachmentPayload(fileObj, f.uploadedUrl!, f.thumbUrl);\n });\n\n // Build message\n const message: Record<string, any> = { text };\n\n // The API does not accept attachment arrays during standard text editing\n if (!editingMessage && attachments.length > 0) {\n message.attachments = attachments;\n }\n\n if (isTeamChannel) {\n message.mentioned_all = payload.mentioned_all;\n message.mentioned_users = payload.mentioned_users;\n }\n let sendPromise;\n\n if (editingMessage?.id) {\n sendPromise = activeChannel.editMessage(editingMessage.id, message as any);\n } else {\n if (quotedMessage?.id) {\n message.quoted_message_id = quotedMessage.id;\n }\n sendPromise = activeChannel.sendMessage(message as any);\n }\n\n // --- 0. OPTIMISTIC UI UPDATE ---\n // Instantly injects the `status: 'sending'` message scaffold from SDK into the React map\n syncMessages();\n\n // --- 1. CLEAR UI IMMEDIATELY (FIRE AND FORGET) ---\n // Clear successful files\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n\n const errorFiles = files.filter((f) => f.status === 'error');\n setFiles(errorFiles);\n setHasContent(errorFiles.length > 0);\n\n reset();\n clearQuotedMessage?.();\n clearEditingMessage?.();\n onSend?.(payload.text);\n // Stop typing indicator immediately on send\n activeChannel?.stopTyping();\n\n // --- 2. DELEGATE TO WEBSOCKET ---\n // The API call runs in background. We do not block the UI for resolution.\n // Message lists will automatically update when the backend blasts the `message.new` WS event.\n sendPromise.catch((err: Error) => {\n console.error('Failed to send message over API:', err);\n // Sync React to render the SDK's internal 'status: failed' UI state\n syncMessages();\n });\n } catch (err) {\n console.error('Failed to process message send:', err);\n } finally {\n isProcessingRef.current = false;\n setSending(false);\n requestAnimationFrame(() => {\n editableRef.current?.focus();\n });\n }\n }, [\n activeChannel,\n hasContent,\n sending,\n buildPayload,\n reset,\n onSend,\n isTeamChannel,\n files,\n onBeforeSend,\n syncMessages,\n editableRef,\n setFiles,\n setHasContent,\n ]);\n\n return { sending, handleSend };\n}\n","import React from 'react';\n\n/* ----------------------------------------------------------\n Default sub-components for MessageInput\n ---------------------------------------------------------- */\n\nexport const DefaultSendButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__send-btn\"\n onClick={onClick}\n disabled={disabled}\n >\n Send\n </button>\n));\nDefaultSendButton.displayName = 'DefaultSendButton';\n\nexport const DefaultAttachButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__attach-btn\"\n onClick={onClick}\n type=\"button\"\n aria-label=\"Attach files\"\n disabled={disabled}\n >\n 📎\n </button>\n));\nDefaultAttachButton.displayName = 'DefaultAttachButton';\n\nexport const DefaultEmojiButton: React.FC<{ active: boolean; onClick: () => void }> = React.memo(({\n active,\n onClick,\n}) => (\n <button\n className={`ermis-message-input__emoji-btn${active ? ' ermis-message-input__emoji-btn--active' : ''}`}\n onClick={onClick}\n type=\"button\"\n aria-label=\"Emoji\"\n >\n 😀\n </button>\n));\nDefaultEmojiButton.displayName = 'DefaultEmojiButton';\n","import React, { useEffect, useRef } from 'react';\nimport { VList, VListHandle } from 'virtua';\nimport { Avatar } from './Avatar';\nimport type { MentionSuggestionsProps } from '../types';\n\nexport type { MentionSuggestionsProps } from '../types';\n\n// Estimated item height\nconst ITEM_HEIGHT = 42; \n\nexport const MentionSuggestions: React.FC<MentionSuggestionsProps> = React.memo(({\n members,\n highlightIndex,\n onSelect,\n}) => {\n const listRef = useRef<VListHandle>(null);\n\n // Auto-scroll highlighted item into view\n useEffect(() => {\n // VList uses scrollToIndex\n listRef.current?.scrollToIndex(highlightIndex);\n }, [highlightIndex]);\n\n if (members.length === 0) return null;\n\n // Calculate dynamic height based on item count, cap at 200px\n const listHeight = Math.min(members.length * ITEM_HEIGHT, 200);\n\n return (\n <div className=\"ermis-mention-suggestions\" style={{ overflow: 'hidden' }}>\n <VList ref={listRef} style={{ height: listHeight }}>\n {members.map((member, index) => (\n <div\n key={member.id}\n className={`ermis-mention-suggestions__item${\n index === highlightIndex ? ' ermis-mention-suggestions__item--highlighted' : ''\n }`}\n onMouseDown={(e) => {\n // Use mousedown (not click) to fire before blur\n e.preventDefault();\n onSelect(member);\n }}\n >\n {member.id === '__all__' ? (\n <div className=\"ermis-mention-suggestions__all-icon\">@</div>\n ) : (\n <Avatar image={member.avatar} name={member.name} size={24} />\n )}\n <span className=\"ermis-mention-suggestions__name\">\n {member.id === '__all__' ? 'all' : member.name}\n </span>\n </div>\n ))}\n </VList>\n </div>\n );\n});\n\nMentionSuggestions.displayName = 'MentionSuggestions';\n","import React from 'react';\nimport { isHeicFile } from '@ermis-network/ermis-chat-sdk';\nimport type { FilesPreviewProps } from '../types';\n\nexport type { FilePreviewItem, FilesPreviewProps } from '../types';\n/**\n * Format file size into human-readable string.\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Get a display icon for non-previewable file types.\n */\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.startsWith('audio/')) return '🎵';\n if (mimeType.startsWith('video/')) return '🎬';\n if (mimeType.includes('pdf')) return '📄';\n if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('tar')) return '📦';\n return '📎';\n}\n\n/**\n * FilesPreview — renders selected files with thumbnails and remove buttons.\n * Shown above the text input area in MessageInput.\n */\nexport const FilesPreview: React.FC<FilesPreviewProps> = React.memo(({ files, onRemove }) => {\n if (files.length === 0) return null;\n\n return (\n <div className=\"ermis-files-preview\">\n {files.map((item) => {\n const fileType = item.file?.type || item.originalAttachment?.mime_type || '';\n const fileName = item.file?.name || item.originalAttachment?.title || 'Unknown file';\n const fileSize = item.file?.size || item.originalAttachment?.file_size || 0;\n\n const isHeic = item.file ? isHeicFile(item.file) : (fileType === 'image/heic' || fileType === 'image/heif');\n const isImage = fileType.startsWith('image/') && !isHeic;\n const isVideo = fileType.startsWith('video/');\n const isUploading = item.status === 'uploading';\n const hasError = item.status === 'error';\n\n const previewUrl = item.previewUrl || item.originalAttachment?.image_url || item.originalAttachment?.asset_url;\n\n return (\n <div\n key={item.id}\n className={`ermis-files-preview__item${hasError ? ' ermis-files-preview__item--error' : ''}`}\n >\n {/* Remove button */}\n <button\n className=\"ermis-files-preview__remove\"\n onClick={() => onRemove(item.id)}\n aria-label=\"Remove file\"\n type=\"button\"\n >\n ✕\n </button>\n\n {/* Preview content */}\n {isImage && previewUrl ? (\n <img\n className=\"ermis-files-preview__thumb\"\n src={previewUrl}\n alt={fileName}\n />\n ) : isVideo && previewUrl ? (\n <video\n className=\"ermis-files-preview__thumb\"\n src={previewUrl}\n muted\n />\n ) : (\n <div className=\"ermis-files-preview__file-icon\">\n <span>{getFileIcon(fileType)}</span>\n </div>\n )}\n\n {/* File info */}\n <div className=\"ermis-files-preview__info\">\n <span className=\"ermis-files-preview__name\">{fileName}</span>\n <span className=\"ermis-files-preview__size\">{formatFileSize(Number(fileSize))}</span>\n </div>\n\n {/* Upload status overlay */}\n {isUploading && (\n <div className=\"ermis-files-preview__uploading\">\n <span className=\"ermis-files-preview__spinner\" />\n </div>\n )}\n\n {/* Error overlay */}\n {hasError && (\n <div className=\"ermis-files-preview__error-badge\" title={item.error}>\n ⚠\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n});\n\nFilesPreview.displayName = 'FilesPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport type { ReplyPreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const ReplyPreview: React.FC<ReplyPreviewProps> = React.memo(({\n message,\n onDismiss,\n replyingToLabel = 'Replying to',\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n \n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = isStickerMessage(message);\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{replyingToLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel reply\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nReplyPreview.displayName = 'ReplyPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const EditPreview: React.FC<{\n message: FormatMessageResponse;\n onDismiss: () => void;\n}> = React.memo(({\n message,\n onDismiss,\n editingMessageLabel = 'Editing message',\n}: any) => {\n console.log('--message--', message)\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n\n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = isStickerMessage(message);\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{editingMessageLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel edit\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nEditPreview.displayName = 'EditPreview';\n","import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { Avatar } from '../Avatar';\nimport { DefaultChannelInfoTabs } from './ChannelInfoTabs';\nimport { AddMemberModal } from './AddMemberModal';\nimport { EditChannelModal } from './EditChannelModal';\nimport { TopicModal } from '../TopicModal';\nimport { MessageSearchPanel } from './MessageSearchPanel';\nimport { ChannelSettingsPanel } from './ChannelSettingsPanel';\nimport type {\n ChannelInfoProps,\n ChannelInfoHeaderProps,\n ChannelInfoCoverProps,\n ChannelInfoActionsProps,\n} from '../../types';\nimport { useChannelMembers, useChannelProfile } from '../../hooks/useChannelData';\nimport { isGroupChannel, isTopicChannel } from '../../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const DefaultChannelInfoHeader: React.FC<ChannelInfoHeaderProps> = React.memo(({ title, onClose }) => {\n return (\n <div className=\"ermis-channel-info__header\">\n <h3 className=\"ermis-channel-info__title\">{title}</h3>\n {onClose && (\n <button className=\"ermis-channel-info__close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n )}\n </div>\n );\n});\nDefaultChannelInfoHeader.displayName = 'DefaultChannelInfoHeader';\n\nexport const DefaultChannelInfoCover: React.FC<ChannelInfoCoverProps> = React.memo(({ channelName, channelImage, channelDescription, AvatarComponent, canEdit, onEditClick, isPublic, isTeamChannel, parentChannelName, isTopic }) => {\n const renderAvatar = () => {\n if (isTopic && channelImage && channelImage.startsWith('emoji://')) {\n const emoji = channelImage.replace('emoji://', '');\n return (\n <div className=\"ermis-channel-info__topic-emoji-avatar\">\n {emoji}\n </div>\n );\n }\n return <AvatarComponent image={channelImage} name={channelName} size={80} className=\"ermis-channel-info__avatar\" />;\n };\n\n return (\n <div className=\"ermis-channel-info__cover\">\n {renderAvatar()}\n <div className=\"ermis-channel-info__name-row\">\n <h2 className=\"ermis-channel-info__name\">{channelName}</h2>\n {canEdit && onEditClick && (\n <button className=\"ermis-channel-info__cover-edit-btn\" onClick={onEditClick} aria-label=\"Edit channel\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\n </svg>\n </button>\n )}\n </div>\n {parentChannelName && (\n <div className=\"ermis-channel-info__parent-name\">\n {parentChannelName}\n </div>\n )}\n {isTeamChannel && (\n <span className={`ermis-channel-info__type-badge ${isPublic ? 'ermis-channel-info__type-badge--public' : 'ermis-channel-info__type-badge--private'}`}>\n {isPublic ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n {isPublic ? 'Public' : 'Private'}\n </span>\n )}\n {channelDescription && (\n <p className=\"ermis-channel-info__description\">{channelDescription}</p>\n )}\n </div>\n );\n});\nDefaultChannelInfoCover.displayName = 'DefaultChannelInfoCover';\n\nexport const DefaultChannelInfoActions: React.FC<ChannelInfoActionsProps> = React.memo(({\n onSearchClick, onSettingsClick, onLeaveChannel, onDeleteChannel,\n onBlockUser, onUnblockUser, onCloseTopic, onReopenTopic,\n isTeamChannel, isTopic, isClosedTopic, isBlocked, currentUserRole,\n searchLabel = 'Search', settingsLabel = 'Settings', deleteLabel = 'Delete', leaveLabel = 'Leave',\n blockLabel = 'Block', unblockLabel = 'Unblock', closeTopicLabel = 'Close Topic', reopenTopicLabel = 'Reopen Topic'\n}) => {\n return (\n <div className=\"ermis-channel-info__actions\">\n <button className=\"ermis-channel-info__action-btn\" onClick={onSearchClick} disabled={isBlocked}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n </div>\n <span>{searchLabel}</span>\n </button>\n {isTeamChannel && canManageChannel(currentUserRole) && (\n <button className=\"ermis-channel-info__action-btn\" onClick={onSettingsClick}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path>\n </svg>\n </div>\n <span>{settingsLabel}</span>\n </button>\n )}\n {isTeamChannel && (\n currentUserRole === CHANNEL_ROLES.OWNER ? (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onDeleteChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\"></polyline>\n <path d=\"M19 6V20a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </div>\n <span>{deleteLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onLeaveChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"></path>\n <polyline points=\"16 17 21 12 16 7\"></polyline>\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"></line>\n </svg>\n </div>\n <span>{leaveLabel}</span>\n </button>\n )\n )}\n {/* Topics: Close/Reopen Topic for owner/moder */}\n {isTopic && canManageChannel(currentUserRole) && (\n isClosedTopic ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onReopenTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 9.9-1\" />\n </svg>\n </div>\n <span>{reopenTopicLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onCloseTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n </div>\n <span>{closeTopicLabel}</span>\n </button>\n )\n )}\n {/* Block/Unblock — messaging (1-1) channels only */}\n {!isTeamChannel && !isTopic && (\n isBlocked ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onUnblockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span>{unblockLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onBlockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span>{blockLabel}</span>\n </button>\n )\n )}\n </div>\n );\n});\nDefaultChannelInfoActions.displayName = 'DefaultChannelInfoActions';\n\nexport const ChannelInfo: React.FC<ChannelInfoProps> = React.memo((props) => {\n const {\n channel: channelProp,\n className = '',\n AvatarComponent = Avatar,\n onClose,\n title: titleProp,\n HeaderComponent = DefaultChannelInfoHeader,\n CoverComponent = DefaultChannelInfoCover,\n ActionsComponent = DefaultChannelInfoActions,\n TabsComponent = DefaultChannelInfoTabs,\n AddMemberModalComponent,\n EditChannelModalComponent,\n actionsSearchLabel,\n actionsSettingsLabel,\n actionsDeleteLabel,\n actionsLeaveLabel,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n onSearchClick,\n onLeaveChannel: onLeaveChannelProp,\n onDeleteChannel: onDeleteChannelProp,\n onAddMemberClick,\n onRemoveMember: onRemoveMemberProp,\n onBanMember: onBanMemberProp,\n onUnbanMember: onUnbanMemberProp,\n onPromoteMember: onPromoteMemberProp,\n onDemoteMember: onDemoteMemberProp,\n // Add Member customization\n addMemberModalTitle,\n addMemberSearchPlaceholder,\n addMemberLoadingText,\n addMemberEmptyText,\n addMemberAddLabel,\n addMemberAddingLabel,\n addMemberAddedLabel,\n addMemberButtonLabel,\n AddMemberButtonComponent,\n // Edit Channel customization\n onEditChannel: onEditChannelProp,\n editChannelModalTitle,\n editChannelNameLabel,\n editChannelDescriptionLabel,\n editChannelNamePlaceholder,\n editChannelDescriptionPlaceholder,\n editChannelPublicLabel,\n editChannelSaveLabel,\n editChannelCancelLabel,\n editChannelSavingLabel,\n editChannelChangeAvatarLabel,\n editChannelImageAccept,\n editChannelMaxImageSize,\n editChannelMaxImageSizeError,\n // Block/Unblock customization (messaging channels)\n onBlockUser: onBlockUserProp,\n onUnblockUser: onUnblockUserProp,\n actionsBlockLabel,\n actionsUnblockLabel,\n actionsCloseTopicLabel,\n actionsReopenTopicLabel,\n // Settings panel customizations\n settingsWorkspaceTopicsTitle,\n settingsTopicsFeatureName,\n settingsTopicsFeatureDescription,\n } = props;\n\n const { activeChannel, client } = useChatClient();\n const channel = channelProp || activeChannel;\n const { isBanned } = useBannedState(channel, client?.userID);\n const { isBlocked } = useBlockedState(channel, client?.userID);\n\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const isTeamChannel = isGroupChannel(channel);\n const isTopic = isTopicChannel(channel);\n const isClosedTopic = channel?.data?.is_closed_topic === true;\n const title = titleProp !== undefined ? titleProp : (isTopic ? 'Topic Info' : 'Channel Info');\n\n const parentCid = channel?.data?.parent_cid as string | undefined;\n const parentChannel = parentCid && client ? client.activeChannels[parentCid] : undefined;\n let parentChannelName = parentChannel?.data?.name || (parentCid ? 'Unknown' : undefined);\n\n const handleDeleteChannel = useCallback(async () => {\n if (onDeleteChannelProp) return onDeleteChannelProp();\n if (!channel) return;\n try {\n await channel.delete();\n } catch (e) {\n console.error(\"Error deleting channel\", e);\n }\n }, [channel, onDeleteChannelProp]);\n\n const handleLeaveChannel = useCallback(async () => {\n if (onLeaveChannelProp) return onLeaveChannelProp();\n if (!channel || !currentUserId) return;\n try {\n await channel.removeMembers([currentUserId]);\n } catch (e) {\n console.error(\"Error leaving channel\", e);\n }\n }, [channel, currentUserId, onLeaveChannelProp]);\n\n const handleRemoveMember = useCallback(async (memberId: string) => {\n if (onRemoveMemberProp) return onRemoveMemberProp(memberId);\n if (!channel) return;\n try {\n await channel.removeMembers([memberId]);\n } catch (e) {\n console.error(\"Error removing member\", e);\n }\n }, [channel, onRemoveMemberProp]);\n\n const handleBanMember = useCallback(async (memberId: string) => {\n if (onBanMemberProp) return onBanMemberProp(memberId);\n if (!channel) return;\n try { await channel.banMembers([memberId]); } catch (e) { console.error(\"Error banning member\", e); }\n }, [channel, onBanMemberProp]);\n\n const handleUnbanMember = useCallback(async (memberId: string) => {\n if (onUnbanMemberProp) return onUnbanMemberProp(memberId);\n if (!channel) return;\n try { await channel.unbanMembers([memberId]); } catch (e) { console.error(\"Error unbanning member\", e); }\n }, [channel, onUnbanMemberProp]);\n\n const handlePromoteMember = useCallback(async (memberId: string) => {\n if (onPromoteMemberProp) return onPromoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.addModerators([memberId]); } catch (e) { console.error(\"Error promoting member\", e); }\n }, [channel, onPromoteMemberProp]);\n\n const handleDemoteMember = useCallback(async (memberId: string) => {\n if (onDemoteMemberProp) return onDemoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.demoteModerators([memberId]); } catch (e) { console.error(\"Error demoting member\", e); }\n }, [channel, onDemoteMemberProp]);\n\n const handleBlockUser = useCallback(async () => {\n if (onBlockUserProp) return onBlockUserProp();\n if (!channel) return;\n try { await channel.blockUser(); } catch (e) { console.error('Error blocking user', e); }\n }, [channel, onBlockUserProp]);\n\n const handleUnblockUser = useCallback(async () => {\n if (onUnblockUserProp) return onUnblockUserProp();\n if (!channel) return;\n try { await channel.unblockUser(); } catch (e) { console.error('Error unblocking user', e); }\n }, [channel, onUnblockUserProp]);\n\n const handleCloseTopic = useCallback(async () => {\n if (!channel || !parentChannel) return;\n try { await parentChannel.closeTopic(channel.cid); } catch (e) { console.error('Error closing topic', e); }\n }, [channel, parentChannel]);\n\n const handleReopenTopic = useCallback(async () => {\n if (!channel || !parentChannel) return;\n try { await parentChannel.reopenTopic(channel.cid); } catch (e) { console.error('Error reopening topic', e); }\n }, [channel, parentChannel]);\n\n const { members } = useChannelMembers(channel);\n const { channelName: profileChannelName, channelImage, channelDescription } = useChannelProfile(channel);\n\n let finalChannelName = profileChannelName;\n let finalParentChannelName = parentChannelName;\n\n // If this is the proxy 'general' channel, show the team name as the main name and hide the parent name.\n if (isGroupChannel(channel) && channel?.data?.name === 'general' && channel.cid) {\n const realChannelName = client?.activeChannels[channel.cid]?.data?.name;\n if (realChannelName && realChannelName !== 'general') {\n finalChannelName = realChannelName;\n finalParentChannelName = undefined;\n }\n }\n\n const [showAddMemberModal, setShowAddMemberModal] = useState(false);\n const [showEditChannelModal, setShowEditChannelModal] = useState(false);\n const [showEditTopicModal, setShowEditTopicModal] = useState(false);\n const [showSearchPanel, setShowSearchPanel] = useState(false);\n const [showSettingsPanel, setShowSettingsPanel] = useState(false);\n\n // Permission: only owner or moderator can edit channel info (banned users cannot)\n const canEditChannel = (isTeamChannel || isTopic) && !isBanned && canManageChannel(currentUserRole);\n\n const handleEditChannelClick = useCallback(() => {\n if (isTopic) {\n setShowEditTopicModal(true);\n } else {\n setShowEditChannelModal(true);\n }\n }, [isTopic]);\n\n const handleAddMemberClick = useCallback(() => {\n if (onAddMemberClick) return onAddMemberClick();\n setShowAddMemberModal(true);\n }, [onAddMemberClick]);\n\n\n\n if (!channel) return null;\n\n return (\n <div className={`ermis-channel-info ${className}`.trim()}>\n <HeaderComponent title={title} onClose={onClose} />\n\n <CoverComponent\n channelName={finalChannelName}\n channelImage={channelImage}\n channelDescription={channelDescription}\n AvatarComponent={AvatarComponent}\n canEdit={canEditChannel}\n onEditClick={handleEditChannelClick}\n isPublic={Boolean(channel?.data?.public)}\n isTeamChannel={isTeamChannel}\n parentChannelName={finalParentChannelName}\n isTopic={isTopic}\n />\n\n {isBanned && (\n <div className=\"ermis-channel-info__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\"></line>\n </svg>\n <span className=\"ermis-channel-info__banned-banner-text\">You have been banned from this channel</span>\n </div>\n )}\n {!isBanned && (\n <>\n <ActionsComponent\n onSearchClick={() => setShowSearchPanel(true)}\n onSettingsClick={() => setShowSettingsPanel(true)}\n onLeaveChannel={handleLeaveChannel}\n onDeleteChannel={handleDeleteChannel}\n onBlockUser={handleBlockUser}\n onUnblockUser={handleUnblockUser}\n onCloseTopic={handleCloseTopic}\n onReopenTopic={handleReopenTopic}\n isTeamChannel={isTeamChannel}\n isTopic={isTopic}\n isClosedTopic={isClosedTopic}\n isBlocked={isBlocked}\n currentUserRole={currentUserRole}\n searchLabel={actionsSearchLabel}\n settingsLabel={actionsSettingsLabel}\n deleteLabel={actionsDeleteLabel}\n leaveLabel={actionsLeaveLabel}\n blockLabel={actionsBlockLabel}\n unblockLabel={actionsUnblockLabel}\n closeTopicLabel={actionsCloseTopicLabel}\n reopenTopicLabel={actionsReopenTopicLabel}\n />\n\n <TabsComponent\n channel={channel}\n members={members as any}\n AvatarComponent={AvatarComponent}\n currentUserId={currentUserId}\n currentUserRole={currentUserRole}\n onAddMemberClick={isTeamChannel ? handleAddMemberClick : undefined}\n onRemoveMember={handleRemoveMember}\n onBanMember={handleBanMember}\n onUnbanMember={handleUnbanMember}\n onPromoteMember={handlePromoteMember}\n onDemoteMember={handleDemoteMember}\n addMemberButtonLabel={addMemberButtonLabel}\n AddMemberButtonComponent={AddMemberButtonComponent}\n MemberItemComponent={MemberItemComponent}\n MediaItemComponent={MediaItemComponent}\n LinkItemComponent={LinkItemComponent}\n FileItemComponent={FileItemComponent}\n EmptyStateComponent={EmptyStateComponent}\n LoadingComponent={LoadingComponent}\n />\n\n {showAddMemberModal && (() => {\n const ModalComp = AddMemberModalComponent || AddMemberModal;\n return (\n <ModalComp\n channel={channel}\n currentMembers={members as any}\n onClose={() => setShowAddMemberModal(false)}\n AvatarComponent={AvatarComponent}\n title={addMemberModalTitle}\n searchPlaceholder={addMemberSearchPlaceholder}\n loadingText={addMemberLoadingText}\n emptyText={addMemberEmptyText}\n addLabel={addMemberAddLabel}\n addingLabel={addMemberAddingLabel}\n addedLabel={addMemberAddedLabel}\n />\n );\n })()}\n\n {showEditChannelModal && (() => {\n const EditComp = EditChannelModalComponent || EditChannelModal;\n return (\n <EditComp\n channel={channel}\n onClose={() => setShowEditChannelModal(false)}\n onSave={onEditChannelProp}\n AvatarComponent={AvatarComponent}\n title={editChannelModalTitle}\n nameLabel={editChannelNameLabel}\n descriptionLabel={editChannelDescriptionLabel}\n namePlaceholder={editChannelNamePlaceholder}\n descriptionPlaceholder={editChannelDescriptionPlaceholder}\n publicLabel={editChannelPublicLabel}\n saveLabel={editChannelSaveLabel}\n cancelLabel={editChannelCancelLabel}\n savingLabel={editChannelSavingLabel}\n changeAvatarLabel={editChannelChangeAvatarLabel}\n imageAccept={editChannelImageAccept}\n maxImageSize={editChannelMaxImageSize}\n maxImageSizeError={editChannelMaxImageSizeError}\n />\n );\n })()}\n\n {showEditTopicModal && (() => {\n return (\n <TopicModal\n isOpen={true}\n onClose={() => setShowEditTopicModal(false)}\n topic={channel}\n />\n );\n })()}\n </>\n )}\n\n {/* Search Panel — slides over entire ChannelInfo body */}\n {channel && showSearchPanel && (\n <MessageSearchPanel\n isOpen={showSearchPanel}\n onClose={() => setShowSearchPanel(false)}\n channel={channel}\n AvatarComponent={AvatarComponent}\n />\n )}\n\n {/* Settings Panel — slides over entire ChannelInfo body */}\n {channel && showSettingsPanel && (\n <ChannelSettingsPanel\n isOpen={showSettingsPanel}\n onClose={() => setShowSettingsPanel(false)}\n channel={channel}\n workspaceTopicsTitle={settingsWorkspaceTopicsTitle}\n topicsFeatureName={settingsTopicsFeatureName}\n topicsFeatureDescription={settingsTopicsFeatureDescription}\n />\n )}\n </div>\n );\n});\n\nChannelInfo.displayName = 'ChannelInfo';\n","import React, { useState, useEffect, useMemo, useCallback, useDeferredValue } from 'react';\nimport { VList } from 'virtua';\nimport { ROLE_WEIGHTS, MESSAGING_TABS, ALL_TABS, PENDING_STYLE, READY_STYLE } from './utils';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { MediaGridItem, MediaRow } from './MediaGridItem';\nimport { LinkListItem } from './LinkListItem';\nimport { FileListItem } from './FileListItem';\nimport { MemberListItem } from './MemberListItem';\nimport { TabEmptyState, TabLoadingState } from './States';\nimport { MediaLightbox } from '../MediaLightbox';\nimport type { ChannelInfoTabsProps, MediaTab, AttachmentItem, MediaLightboxItem } from '../../types';\nimport { isDirectChannel } from '../../channelTypeUtils';\nimport {\n CHANNEL_ROLES,\n canRemoveTargetMember,\n canBanTargetMember,\n canPromoteTargetMember,\n canDemoteTargetMember\n} from '../../channelRoleUtils';\n\nexport const DefaultChannelInfoTabs: React.FC<ChannelInfoTabsProps> = React.memo(({\n channel,\n members,\n AvatarComponent,\n currentUserId,\n currentUserRole,\n onAddMemberClick,\n onRemoveMember,\n onBanMember,\n onUnbanMember,\n onPromoteMember,\n onDemoteMember,\n addMemberButtonLabel = 'Add Member',\n AddMemberButtonComponent,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n}) => {\n const isMessaging = isDirectChannel(channel);\n const isTopic = Boolean(channel?.data?.parent_cid);\n \n const { isBanned } = useBannedState(channel, currentUserId);\n const { isBlocked } = useBlockedState(channel, currentUserId);\n\n const availableTabs: MediaTab[] = useMemo(() => {\n let tabs = isMessaging ? MESSAGING_TABS : ALL_TABS;\n if (isTopic) {\n tabs = tabs.filter(t => t !== 'members');\n }\n return tabs;\n }, [isMessaging, isTopic]);\n\n const [activeTab, setActiveTab] = useState<MediaTab>(availableTabs[0]);\n const contentTab = useDeferredValue(activeTab);\n const isPending = activeTab !== contentTab;\n\n // Always reset to the first available tab when the user switches channels\n useEffect(() => {\n setActiveTab(availableTabs[0]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel?.cid, availableTabs]);\n\n // Resolve sub-components with defaults\n const MemberItem = MemberItemComponent || MemberListItem;\n const MediaItem = MediaItemComponent || MediaGridItem;\n const LinkItem = LinkItemComponent || LinkListItem;\n const FileItem = FileItemComponent || FileListItem;\n const EmptyState = EmptyStateComponent || TabEmptyState;\n const Loading = LoadingComponent || TabLoadingState;\n\n const [allAttachments, setAllAttachments] = useState<AttachmentItem[]>([]);\n const [loading, setLoading] = useState(true);\n\n const sortedMembers = useMemo(() => {\n return [...members].sort((a, b) => {\n const aWeight = ROLE_WEIGHTS[a.channel_role || CHANNEL_ROLES.MEMBER] || 0;\n const bWeight = ROLE_WEIGHTS[b.channel_role || CHANNEL_ROLES.MEMBER] || 0;\n return bWeight - aWeight;\n });\n }, [members]);\n\n // Categorize attachments by type\n const mediaItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'image' || a.attachment_type === 'video'),\n [allAttachments]\n );\n\n const linkItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'linkPreview'),\n [allAttachments]\n );\n\n const fileItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'file' || a.attachment_type === 'voiceRecording'),\n [allAttachments]\n );\n\n useEffect(() => {\n let active = true;\n\n // Don't fetch media/files if user is banned or blocked\n if (isBanned || isBlocked) {\n setAllAttachments([]);\n setLoading(false);\n return;\n }\n\n const fetchMedia = async () => {\n setLoading(true);\n try {\n const response: any = await channel.queryAttachmentMessages();\n\n if (active) {\n const items = response?.attachments || [];\n setAllAttachments(items);\n }\n } catch (err) {\n console.error(\"Failed to query media for channel info\", err);\n if (active) setAllAttachments([]);\n } finally {\n if (active) setLoading(false);\n }\n };\n\n fetchMedia();\n\n return () => { active = false; };\n }, [channel, isBanned, isBlocked]);\n\n const tabCounts = useMemo<Record<MediaTab, number>>(() => ({\n members: members.length,\n media: mediaItems.length,\n links: linkItems.length,\n files: fileItems.length,\n }), [members.length, mediaItems.length, linkItems.length, fileItems.length]);\n\n const handleOpenUrl = useCallback((url: string) => {\n window.open(url, '_blank', 'noopener,noreferrer');\n }, []);\n\n // Lightbox state for media tab\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [lightboxIndex, setLightboxIndex] = useState(0);\n\n const lightboxItems = useMemo<MediaLightboxItem[]>(() => {\n return mediaItems.map(item => ({\n type: (item.attachment_type === 'video' ? 'video' : 'image') as 'image' | 'video',\n src: item.url,\n alt: item.file_name,\n posterSrc: item.thumb_url || undefined,\n }));\n }, [mediaItems]);\n\n const handleMediaClick = useCallback((url: string) => {\n const idx = mediaItems.findIndex(item => item.url === url);\n if (idx >= 0) {\n setLightboxIndex(idx);\n setLightboxOpen(true);\n }\n }, [mediaItems]);\n\n const closeLightbox = useCallback(() => {\n setLightboxOpen(false);\n }, []);\n\n // Group media into rows of 3 for grid layout inside VList\n const mediaRows = useMemo(() => {\n const rows: AttachmentItem[][] = [];\n for (let i = 0; i < mediaItems.length; i += 3) {\n rows.push(mediaItems.slice(i, i + 3));\n }\n return rows;\n }, [mediaItems]);\n\n // Build VList children based on contentTab (deferred)\n const vlistChildren = useMemo(() => {\n switch (contentTab) {\n case 'members': {\n const items: React.ReactNode[] = [];\n if (onAddMemberClick) {\n if (AddMemberButtonComponent) {\n items.push(\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <AddMemberButtonComponent onClick={onAddMemberClick} label={addMemberButtonLabel} />\n </div>\n );\n } else {\n items.push(\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <button className=\"ermis-channel-info__add-member-btn\" onClick={onAddMemberClick}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"></path>\n <circle cx=\"8.5\" cy=\"7\" r=\"4\"></circle>\n <line x1=\"20\" y1=\"8\" x2=\"20\" y2=\"14\"></line>\n <line x1=\"23\" y1=\"11\" x2=\"17\" y2=\"11\"></line>\n </svg>\n {addMemberButtonLabel}\n </button>\n </div>\n );\n }\n }\n sortedMembers.forEach(member => {\n const role = member.channel_role || CHANNEL_ROLES.MEMBER;\n const isTargetRemovable = canRemoveTargetMember(currentUserRole, role);\n\n const canRemove = Boolean(\n isTargetRemovable &&\n member.user_id !== currentUserId\n );\n\n const canBan = Boolean(\n canBanTargetMember(currentUserRole, role) &&\n member.user_id !== currentUserId &&\n !member.banned\n );\n\n const canUnban = Boolean(\n canBanTargetMember(currentUserRole, role) &&\n member.user_id !== currentUserId &&\n member.banned\n );\n\n const canPromote = canPromoteTargetMember(currentUserRole, role) && member.user_id !== currentUserId;\n\n const canDemote = canDemoteTargetMember(currentUserRole, role) && member.user_id !== currentUserId;\n\n items.push(\n <MemberItem\n key={member?.user_id}\n member={member}\n AvatarComponent={AvatarComponent}\n onRemove={onRemoveMember}\n canRemove={canRemove}\n onBan={onBanMember}\n canBan={canBan}\n onUnban={onUnbanMember}\n canUnban={canUnban}\n onPromote={onPromoteMember}\n canPromote={canPromote}\n onDemote={onDemoteMember}\n canDemote={canDemote}\n />\n );\n });\n return items;\n }\n case 'media':\n if (MediaItem === MediaGridItem) {\n // Default: use grid rows\n return mediaRows.map((row, rowIdx) => (\n <MediaRow key={row[0]?.id || rowIdx} row={row} onClick={handleMediaClick} />\n ));\n }\n // Custom: render each item individually\n return mediaItems.map((item, idx) => (\n <MediaItem key={item.id || idx} item={item} onClick={handleMediaClick} />\n ));\n case 'links':\n return linkItems.map((item, idx) => (\n <LinkItem key={item.id || idx} item={item} />\n ));\n case 'files':\n return fileItems.map((item, idx) => (\n <FileItem key={item.id || idx} item={item} onClick={handleOpenUrl} />\n ));\n default:\n return [];\n }\n }, [contentTab, sortedMembers, mediaRows, mediaItems, linkItems, fileItems, onAddMemberClick, AvatarComponent, handleMediaClick, handleOpenUrl, MemberItem, MediaItem, LinkItem, FileItem]);\n\n // Check if content is empty for the content tab (deferred)\n const isTabEmpty = vlistChildren.length === 0 && !(loading && contentTab !== 'members');\n const emptyLabel = contentTab === 'members' ? 'members' : contentTab;\n\n return (\n <div className=\"ermis-channel-info__section ermis-channel-info__media-section\">\n <div className=\"ermis-channel-info__media-tabs\">\n {availableTabs.map(tab => (\n <button\n key={tab}\n className={`ermis-channel-info__media-tab ${activeTab === tab ? 'ermis-channel-info__media-tab--active' : ''}`}\n onClick={() => setActiveTab(tab)}\n >\n <span className=\"ermis-channel-info__media-tab-label\">\n {tab.charAt(0).toUpperCase() + tab.slice(1)}\n </span>\n {tabCounts[tab] > 0 && (\n <span className=\"ermis-channel-info__media-tab-count\">{tabCounts[tab]}</span>\n )}\n </button>\n ))}\n </div>\n\n <div\n className=\"ermis-channel-info__media-content\"\n style={isPending ? PENDING_STYLE : READY_STYLE}\n >\n {loading && contentTab !== 'members' ? <Loading /> : isTabEmpty ? <EmptyState label={emptyLabel} /> : (\n <VList style={{ height: '100%' }}>\n {vlistChildren}\n </VList>\n )}\n </div>\n\n {/* Media Lightbox */}\n {lightboxItems.length > 0 && (\n <MediaLightbox\n items={lightboxItems}\n initialIndex={lightboxIndex}\n isOpen={lightboxOpen}\n onClose={closeLightbox}\n />\n )}\n </div>\n );\n});\n","import React, { useState, useMemo } from 'react';\nimport { preloadImage, isImagePreloaded } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const MediaGridItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const src = item.thumb_url || item.url;\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => { preloadImage(src); }, [src]);\n\n // Fallback checks for browser cache when JS preload didn't catch it\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const isVideo = item.attachment_type === 'video';\n\n return (\n <div\n className=\"ermis-channel-info__media-item\"\n onClick={() => onClick(item.url)}\n title={item.file_name}\n >\n {/* Shimmer placeholder while loading */}\n {!loaded && <div className=\"ermis-channel-info__media-shimmer\" />}\n\n {isVideo ? (\n <div className=\"ermis-channel-info__media-video-thumb\">\n {item.thumb_url ? (\n <img\n ref={imgRef}\n src={item.thumb_url}\n alt={item.file_name || 'video'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n ) : (\n <video\n src={item.url}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n <div className=\"ermis-channel-info__media-play-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n ) : (\n <img\n ref={imgRef}\n src={src}\n alt={item.file_name || 'media'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(MediaGridItem as any).displayName = 'MediaGridItem';\n\nexport const MediaRow = React.memo(({ row, onClick }: { row: AttachmentItem[], onClick: (url: string) => void }) => {\n return (\n <div className=\"ermis-channel-info__media-grid-row\">\n {row.map(item => (\n <MediaGridItem key={item.id} item={item} onClick={onClick} />\n ))}\n {row.length < 3 && Array.from({ length: 3 - row.length }).map((_, i) => (\n <div key={`empty-${i}`} className=\"ermis-channel-info__media-item ermis-channel-info__media-item--empty\" />\n ))}\n </div>\n );\n}, (prev, next) => {\n if (prev.row.length !== next.row.length) return false;\n return prev.row.every((item, i) => item.id === next.row[i].id);\n});\n(MediaRow as any).displayName = 'MediaRow';\n","import React, { useState, useMemo } from 'react';\nimport { formatRelativeDate, extractDomain, isImagePreloaded, preloadImage } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const LinkListItem: React.FC<{ item: AttachmentItem }> = React.memo(({ item }) => {\n const displayUrl = item.og_scrape_url || item.title_link || item.url;\n const domain = extractDomain(displayUrl);\n\n // Preload link preview image if available\n const imgSrc = item.image_url;\n const alreadyCached = imgSrc ? isImagePreloaded(imgSrc) : true;\n const [imgLoaded, setImgLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => { if (imgSrc) preloadImage(imgSrc); }, [imgSrc]);\n\n React.useEffect(() => {\n if (!imgLoaded && imgRef.current?.complete) {\n setImgLoaded(true);\n }\n }, [imgLoaded, imgSrc]);\n\n return (\n <a\n className=\"ermis-channel-info__link-item\"\n href={displayUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <div className=\"ermis-channel-info__link-icon\">\n {imgSrc ? (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {!imgLoaded && <div className=\"ermis-channel-info__media-shimmer\" style={{ borderRadius: '8px' }} />}\n <img\n ref={imgRef}\n src={imgSrc}\n alt=\"\"\n className=\"ermis-channel-info__link-preview-img\"\n loading=\"lazy\"\n onLoad={() => setImgLoaded(true)}\n style={{ opacity: imgLoaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n </div>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-channel-info__link-content\">\n <span className=\"ermis-channel-info__link-title\">\n {item.title || item.file_name || domain}\n </span>\n <span className=\"ermis-channel-info__link-domain\">{domain}</span>\n </div>\n <span className=\"ermis-channel-info__link-date\">{formatRelativeDate(item.created_at)}</span>\n </a>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(LinkListItem as any).displayName = 'LinkListItem';\n","import React from 'react';\nimport { formatFileSize, formatRelativeDate, getDisplayName } from '../../utils';\nimport { getFileIcon } from './utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const FileListItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const displayName = getDisplayName(item.file_name);\n const ext = item.file_name.split('.').pop()?.toUpperCase() || 'FILE';\n\n return (\n <div\n className=\"ermis-channel-info__file-item\"\n onClick={() => onClick(item.url)}\n >\n <div className=\"ermis-channel-info__file-icon\">\n {getFileIcon(item.content_type, item.file_name)}\n <span className=\"ermis-channel-info__file-ext\">{ext}</span>\n </div>\n <div className=\"ermis-channel-info__file-info\">\n <span className=\"ermis-channel-info__file-name\" title={item.file_name}>\n {displayName}\n </span>\n <div className=\"ermis-channel-info__file-meta\">\n <span>{formatFileSize(item.content_length)}</span>\n <span className=\"ermis-channel-info__file-meta-dot\">·</span>\n <span>{formatRelativeDate(item.created_at)}</span>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__file-download\"\n onClick={(e) => {\n e.stopPropagation();\n onClick(item.url);\n }}\n aria-label=\"Download\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(FileListItem as any).displayName = 'FileListItem';\n","import React, { useState } from 'react';\nimport { Dropdown } from '../Dropdown';\nimport type { ChannelInfoMemberItemProps } from '../../types';\nimport { CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const MemberListItem = React.memo(({\n member, AvatarComponent, \n onRemove, canRemove, \n onBan, canBan, \n onUnban, canUnban, \n onPromote, canPromote, \n onDemote, canDemote \n}: ChannelInfoMemberItemProps) => {\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const isOpen = anchorRect !== null;\n\n if (!member) return null;\n const role = member.channel_role || CHANNEL_ROLES.MEMBER;\n const hasActions = canRemove || canBan || canUnban || canPromote || canDemote;\n\n return (\n <div className=\"ermis-channel-info__member-item\">\n <AvatarComponent image={member.user?.avatar} name={member.user?.name || member.user?.id} size={36} />\n <div className=\"ermis-channel-info__member-info\">\n <span className=\"ermis-channel-info__member-name\">{member.user?.name || member.user?.id}</span>\n <span className={`ermis-channel-info__member-role ermis-channel-info__member-role--${role.toLowerCase()}`}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </span>\n </div>\n \n {hasActions && (\n <>\n <button\n className=\"ermis-channel-info__member-actions-btn\"\n onClick={(e) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n }}\n aria-label=\"Member actions\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n \n <Dropdown\n isOpen={isOpen}\n anchorRect={anchorRect}\n onClose={() => setAnchorRect(null)}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {canPromote && onPromote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onPromote(member.user?.id || member.user_id); setAnchorRect(null); }}>Promote to Moder</button>\n )}\n {canDemote && onDemote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onDemote(member.user?.id || member.user_id); setAnchorRect(null); }}>Demote to Member</button>\n )}\n {canBan && onBan && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onBan(member.user?.id || member.user_id); setAnchorRect(null); }}>Ban Member</button>\n )}\n {canUnban && onUnban && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onUnban(member.user?.id || member.user_id); setAnchorRect(null); }}>Unban Member</button>\n )}\n {canRemove && onRemove && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onRemove(member.user?.id || member.user_id); setAnchorRect(null); }}>Remove from Channel</button>\n )}\n </div>\n </Dropdown>\n </>\n )}\n </div>\n );\n}, (prev, next) => {\n return prev.member?.user_id === next.member?.user_id &&\n prev.member?.channel_role === next.member?.channel_role &&\n prev.member?.banned === next.member?.banned &&\n prev.canRemove === next.canRemove &&\n prev.canBan === next.canBan &&\n prev.canUnban === next.canUnban &&\n prev.canPromote === next.canPromote &&\n prev.canDemote === next.canDemote;\n});\n(MemberListItem as any).displayName = 'MemberListItem';\n","import React from 'react';\n\nexport const TabEmptyState: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-channel-info__media-empty\">\n <div className=\"ermis-channel-info__media-empty-icon\">\n {label === 'media' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )}\n {label === 'links' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </svg>\n )}\n {label === 'files' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n )}\n </div>\n <span>No {label} shared yet</span>\n </div>\n));\n(TabEmptyState as any).displayName = 'TabEmptyState';\n\nexport const TabLoadingState: React.FC = React.memo(() => (\n <div className=\"ermis-channel-info__media-loading\">\n <div className=\"ermis-channel-info__media-spinner\" />\n </div>\n));\n(TabLoadingState as any).displayName = 'TabLoadingState';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal } from '../Modal';\nimport { UserPicker } from '../UserPicker';\nimport { Avatar } from '../Avatar';\nimport type { AddMemberModalProps, UserPickerUser } from '../../types';\n\nexport const AddMemberModal: React.FC<AddMemberModalProps> = ({\n channel,\n currentMembers,\n onClose,\n AvatarComponent = Avatar,\n title = 'Add Member',\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n addLabel = 'Add',\n addingLabel = 'Adding...',\n addedLabel = 'Added',\n UserItemComponent,\n SearchInputComponent,\n}) => {\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n const [isAdding, setIsAdding] = useState(false);\n\n // Exclude existing members from the picker\n const excludeUserIds = useMemo(\n () => currentMembers.map((m: any) => m.user_id),\n [currentMembers],\n );\n\n\n const handleSelectionChange = useCallback((users: UserPickerUser[]) => {\n setSelectedUsers(users);\n }, []);\n\n const handleAdd = useCallback(async () => {\n if (selectedUsers.length === 0 || isAdding) return;\n try {\n setIsAdding(true);\n await channel.addMembers(selectedUsers.map(u => u.id));\n onClose();\n } catch (err) {\n console.error('Failed to add members:', err);\n } finally {\n setIsAdding(false);\n }\n }, [selectedUsers, isAdding, channel, onClose]);\n\n const footer = (\n <button\n className=\"ermis-modal-add-btn\"\n onClick={handleAdd}\n disabled={selectedUsers.length === 0 || isAdding}\n >\n {isAdding\n ? addingLabel\n : `${addLabel} ${selectedUsers.length > 0 ? `(${selectedUsers.length})` : ''}`}\n </button>\n );\n\n return (\n <Modal isOpen onClose={onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <UserPicker\n mode=\"checkbox\"\n onSelectionChange={handleSelectionChange}\n excludeUserIds={excludeUserIds}\n pageSize={30}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n SearchInputComponent={SearchInputComponent}\n searchPlaceholder={searchPlaceholder}\n loadingText={loadingText}\n emptyText={emptyText}\n selectedEmptyLabel=\"Select users to add...\"\n />\n </Modal>\n );\n};\n","import React, { useState, useEffect, useMemo, useCallback, useRef, useTransition } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { VList, type VListHandle } from 'virtua';\nimport type {\n UserPickerProps,\n UserPickerItemProps,\n UserPickerSelectedBoxProps,\n UserPickerUser,\n} from '../types';\n\n/* ---------- Constants ---------- */\nconst DEFAULT_PAGE_SIZE = 30;\nconst SEARCH_DEBOUNCE_MS = 500;\n\n/* ---------- Static styles ---------- */\nconst LIST_STYLE: React.CSSProperties = { height: '100%' };\n\n/* ==========================================================\n Default Sub-Components\n ========================================================== */\n\n/** Check icon for selected state */\nconst CheckIcon: React.FC = () => (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n);\n\n/** Default user row */\nconst DefaultUserItem: React.FC<UserPickerItemProps> = React.memo(({\n user, selected, disabled, mode, onToggle, AvatarComponent,\n}) => {\n const handleClick = useCallback(() => {\n if (!disabled) onToggle(user);\n }, [disabled, onToggle, user]);\n\n const inputClass = [\n 'ermis-user-picker__input',\n mode === 'radio' ? 'ermis-user-picker__input--radio' : 'ermis-user-picker__input--checkbox',\n selected ? 'ermis-user-picker__input--checked' : '',\n ].join(' ');\n\n const itemClass = [\n 'ermis-user-picker__item',\n selected ? 'ermis-user-picker__item--selected' : '',\n disabled ? 'ermis-user-picker__item--disabled' : '',\n ].join(' ');\n\n const detail = user.email || user.phone || '';\n\n return (\n <div className={itemClass} onClick={handleClick} role=\"option\" aria-selected={selected}>\n <div className={inputClass}>\n {selected && <CheckIcon />}\n </div>\n <AvatarComponent image={user.avatar} name={user.name || user.id} size={36} />\n <div className=\"ermis-user-picker__info\">\n <span className=\"ermis-user-picker__name\">{user.name || user.id}</span>\n {detail && <span className=\"ermis-user-picker__detail\">{detail}</span>}\n </div>\n </div>\n );\n});\nDefaultUserItem.displayName = 'DefaultUserItem';\n\n/** Default search input */\nconst DefaultSearchInput: React.FC<{ value: string; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; placeholder: string }> = ({ value, onChange, placeholder }) => (\n <div className=\"ermis-user-picker__search\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={onChange}\n autoFocus\n />\n </div>\n);\n\n/** Default selected users chip box */\nconst DefaultSelectedBox: React.FC<UserPickerSelectedBoxProps> = React.memo(({\n users, onRemove, AvatarComponent, emptyLabel,\n}) => (\n <div className=\"ermis-user-picker__selected-box\">\n {users.length === 0 && emptyLabel && (\n <span className=\"ermis-user-picker__selected-empty\">{emptyLabel}</span>\n )}\n {users.map(u => (\n <div key={u.id} className=\"ermis-user-picker__chip\">\n <AvatarComponent image={u.avatar} name={u.name || u.id} size={20} />\n <span className=\"ermis-user-picker__chip-name\">{u.name || u.id}</span>\n <button\n className=\"ermis-user-picker__chip-remove\"\n onClick={() => onRemove(u.id)}\n aria-label={`Remove ${u.name || u.id}`}\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n));\nDefaultSelectedBox.displayName = 'DefaultSelectedBox';\n\n/* ==========================================================\n UserPicker Component\n ========================================================== */\n\nexport const UserPicker: React.FC<UserPickerProps> = ({\n mode,\n onSelectionChange,\n excludeUserIds,\n initialSelectedUsers,\n pageSize = DEFAULT_PAGE_SIZE,\n AvatarComponent = Avatar,\n UserItemComponent,\n SelectedBoxComponent,\n SearchInputComponent,\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n loadingMoreText = 'Loading more...',\n selectedEmptyLabel,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [allUsers, setAllUsers] = useState<UserPickerUser[]>([]);\n const [page, setPage] = useState(1);\n const [hasMore, setHasMore] = useState(true);\n const [loading, setLoading] = useState(true);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const [remoteUsers, setRemoteUsers] = useState<UserPickerUser[]>([]);\n const [isSearching, setIsSearching] = useState(false);\n\n const [searchInput, setSearchInput] = useState('');\n const [search, setSearch] = useState('');\n const [isPendingFilter, startTransition] = useTransition();\n\n const [selectedMap, setSelectedMap] = useState<Map<string, UserPickerUser>>(() => {\n const map = new Map<string, UserPickerUser>();\n initialSelectedUsers?.forEach(u => map.set(u.id, u));\n return map;\n });\n\n const vlistRef = useRef<VListHandle>(null);\n\n /* ---------- Resolved sub-components ---------- */\n const UserRow = UserItemComponent || DefaultUserItem;\n const SearchInput = SearchInputComponent || DefaultSearchInput;\n const SelectedBox = SelectedBoxComponent || DefaultSelectedBox;\n\n /* ---------- Excluded IDs set ---------- */\n const excludeSet = useMemo(() => new Set(excludeUserIds || []), [excludeUserIds]);\n\n /* ---------- Search handler ---------- */\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearchInput(val);\n startTransition(() => {\n setSearch(val);\n });\n }, [startTransition]);\n\n /* ---------- 1. Fetch initial page ---------- */\n useEffect(() => {\n let active = true;\n const fetchUsers = async () => {\n if (!client) return;\n try {\n setLoading(true);\n const response = await client.queryUsers(String(pageSize), 1);\n if (active && response.data) {\n setAllUsers(response.data);\n setHasMore(response.data.length >= pageSize);\n setPage(1);\n }\n } catch (err) {\n console.error('[UserPicker] Error fetching users:', err);\n } finally {\n if (active) setLoading(false);\n }\n };\n fetchUsers();\n return () => { active = false; };\n }, [client, pageSize]);\n\n /* ---------- 2. Load more (infinite scroll) ---------- */\n const loadMore = useCallback(async () => {\n if (!client || loadingMore || !hasMore || search.trim()) return;\n const nextPage = page + 1;\n setLoadingMore(true);\n try {\n const response = await client.queryUsers(String(pageSize), nextPage);\n if (response.data) {\n setAllUsers(prev => {\n const existingIds = new Set(prev.map(u => u.id));\n const newUsers = response.data.filter((u: UserPickerUser) => !existingIds.has(u.id));\n return [...prev, ...newUsers];\n });\n setHasMore(response.data.length >= pageSize);\n setPage(nextPage);\n }\n } catch (err) {\n console.error('[UserPicker] Error loading more users:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [client, loadingMore, hasMore, page, pageSize, search]);\n\n /* ---------- 3. Local filter ---------- */\n const localFilteredUsers = useMemo(() => {\n const term = search.toLowerCase().trim();\n if (!term) return allUsers;\n return allUsers.filter(u => {\n const name = (u.name || '').toLowerCase();\n const email = (u.email || '').toLowerCase();\n const phone = (u.phone || '').toLowerCase();\n return name.includes(term) || email.includes(term) || phone.includes(term);\n });\n }, [search, allUsers]);\n\n /* ---------- 4. Remote search fallback ---------- */\n useEffect(() => {\n if (!search.trim() || localFilteredUsers.length > 0) {\n setRemoteUsers([]);\n setIsSearching(false);\n return;\n }\n\n let cancelled = false;\n const timer = setTimeout(async () => {\n setIsSearching(true);\n try {\n const response = await client.searchUsers(1, 25, search.trim());\n if (!cancelled && response.data) {\n setRemoteUsers(response.data);\n }\n } catch (err) {\n console.error('[UserPicker] Error searching remote users:', err);\n } finally {\n if (!cancelled) setIsSearching(false);\n }\n }, SEARCH_DEBOUNCE_MS);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [search, localFilteredUsers.length, client]);\n\n /* ---------- 5. Derived display list ---------- */\n const usersToDisplay = (search.trim() && localFilteredUsers.length === 0)\n ? remoteUsers\n : localFilteredUsers;\n const isListLoading = loading || isSearching || isPendingFilter;\n\n /* ---------- 6. Selection handlers ---------- */\n const handleToggle = useCallback((user: UserPickerUser) => {\n // Don't allow toggling disabled users (current user or excluded)\n if (user.id === currentUserId || excludeSet.has(user.id)) return;\n\n setSelectedMap(prev => {\n const next = new Map(prev);\n if (mode === 'radio') {\n // Radio: clear all, set this one (or deselect if same)\n if (next.has(user.id)) {\n next.clear();\n } else {\n next.clear();\n next.set(user.id, user);\n }\n } else {\n // Checkbox: toggle\n if (next.has(user.id)) {\n next.delete(user.id);\n } else {\n next.set(user.id, user);\n }\n }\n return next;\n });\n }, [mode, currentUserId, excludeSet]);\n\n // Notify parent of selection changes\n useEffect(() => {\n onSelectionChange?.(Array.from(selectedMap.values()));\n }, [selectedMap, onSelectionChange]);\n\n const handleRemoveSelected = useCallback((userId: string) => {\n setSelectedMap(prev => {\n const next = new Map(prev);\n next.delete(userId);\n return next;\n });\n }, []);\n\n /* ---------- 7. Scroll handler for infinite scroll ---------- */\n const handleScroll = useCallback((offset: number) => {\n // VList provides scroll offset. We detect near-bottom using the ref\n const el = vlistRef.current;\n if (!el) return;\n // scrollSize = total scroll height, viewportSize = visible height\n const scrollSize = (el as any).scrollSize ?? 0;\n const viewportSize = (el as any).viewportSize ?? 0;\n if (scrollSize > 0 && offset + viewportSize >= scrollSize - 50) {\n loadMore();\n }\n }, [loadMore]);\n\n /* ---------- Render ---------- */\n const selectedArr = useMemo(() => Array.from(selectedMap.values()), [selectedMap]);\n\n return (\n <div className=\"ermis-user-picker\" role=\"listbox\" aria-multiselectable={mode === 'checkbox'}>\n {/* Selected Users Box (checkbox mode only) */}\n {mode === 'checkbox' && (\n <SelectedBox\n users={selectedArr}\n onRemove={handleRemoveSelected}\n AvatarComponent={AvatarComponent}\n emptyLabel={selectedEmptyLabel}\n />\n )}\n\n {/* Search Input */}\n <SearchInput\n value={searchInput}\n onChange={handleSearchChange}\n placeholder={searchPlaceholder}\n />\n\n {/* User List */}\n <div className=\"ermis-user-picker__list\">\n {isListLoading ? (\n <div className=\"ermis-user-picker__loading\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingText}\n </div>\n ) : usersToDisplay.length === 0 ? (\n <div className=\"ermis-user-picker__empty\">{emptyText}</div>\n ) : (\n <VList ref={vlistRef} style={LIST_STYLE} onScroll={handleScroll}>\n {usersToDisplay.map(user => (\n <UserRow\n key={user.id}\n user={user}\n selected={selectedMap.has(user.id)}\n disabled={user.id === currentUserId || excludeSet.has(user.id)}\n mode={mode}\n onToggle={handleToggle}\n AvatarComponent={AvatarComponent}\n />\n ))}\n {loadingMore && (\n <div className=\"ermis-user-picker__load-more\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingMoreText}\n </div>\n )}\n </VList>\n )}\n </div>\n </div>\n );\n};\n\nUserPicker.displayName = 'UserPicker';\n","import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { Modal } from '../Modal';\nimport type { EditChannelModalProps, EditChannelData } from '../../types';\nimport { isGroupChannel } from '../../channelTypeUtils';\n\nconst DEFAULT_MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB\n\nexport const EditChannelModal: React.FC<EditChannelModalProps> = React.memo(({\n channel,\n onClose,\n onSave,\n AvatarComponent,\n title = 'Edit Channel',\n nameLabel = 'Channel Name',\n descriptionLabel = 'Description',\n namePlaceholder = 'Enter channel name',\n descriptionPlaceholder = 'Enter channel description',\n publicLabel = 'Public Channel',\n saveLabel = 'Save',\n cancelLabel = 'Cancel',\n savingLabel = 'Saving...',\n changeAvatarLabel = 'Change Avatar',\n imageAccept = 'image/*',\n maxImageSize = DEFAULT_MAX_IMAGE_SIZE,\n maxImageSizeError = 'Image must be less than 5MB',\n}) => {\n // Original values from channel data\n const originalName = (channel.data?.name as string) || '';\n const originalImage = (channel.data?.image as string) || '';\n const originalDescription = (channel.data?.description as string) || '';\n const originalPublic = Boolean(channel.data?.public);\n const isTeamOrMeetingChannel = isGroupChannel(channel);\n\n // Form state\n const [name, setName] = useState(originalName);\n const [description, setDescription] = useState(originalDescription);\n const [isPublic, setIsPublic] = useState(originalPublic);\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n const [selectedFile, setSelectedFile] = useState<File | null>(null);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Clean up object URL on unmount or when preview changes\n useEffect(() => {\n return () => {\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n };\n }, [previewUrl]);\n\n const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n // Validate it's an image\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n\n // Validate size\n if (file.size > maxImageSize) {\n setError(maxImageSizeError);\n return;\n }\n\n setError(null);\n // Revoke previous preview\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n const url = URL.createObjectURL(file);\n setPreviewUrl(url);\n setSelectedFile(file);\n\n // Reset input so same file can be re-selected\n e.target.value = '';\n }, [maxImageSize, maxImageSizeError, previewUrl]);\n\n const handleAvatarClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Check if anything changed — only send changed fields\n const buildPayload = useCallback((): EditChannelData | null => {\n const payload: EditChannelData = {};\n let hasChanges = false;\n\n if (name.trim() !== originalName) {\n payload.name = name.trim();\n hasChanges = true;\n }\n if (description.trim() !== originalDescription) {\n payload.description = description.trim();\n hasChanges = true;\n }\n if (isTeamOrMeetingChannel && isPublic !== originalPublic) {\n payload.public = isPublic;\n hasChanges = true;\n }\n // Image is handled separately (upload first), but mark as changed\n if (selectedFile) {\n hasChanges = true;\n }\n\n return hasChanges ? payload : null;\n }, [name, description, isPublic, selectedFile, originalName, originalDescription, originalPublic, isTeamOrMeetingChannel]);\n\n const handleSave = useCallback(async () => {\n const payload = buildPayload();\n if (!payload && !selectedFile) {\n onClose();\n return;\n }\n\n setIsSaving(true);\n setError(null);\n\n try {\n // If consumer provides custom save handler, delegate entirely\n if (onSave) {\n if (selectedFile) {\n const response = await channel.sendFile(selectedFile, selectedFile.name, selectedFile.type);\n (payload || {} as EditChannelData).image = response.file;\n }\n await onSave(payload || {});\n onClose();\n return;\n }\n\n // Default save logic\n const finalPayload: EditChannelData = payload || {};\n\n // Upload image if changed\n if (selectedFile) {\n const response = await channel.sendFile(selectedFile, selectedFile.name, selectedFile.type);\n finalPayload.image = response.file;\n }\n\n // Only call update if there's something to update\n if (Object.keys(finalPayload).length > 0) {\n await channel.update(finalPayload as any);\n }\n\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update channel');\n } finally {\n setIsSaving(false);\n }\n }, [buildPayload, selectedFile, onSave, channel, onClose]);\n\n // Determine displayed avatar image\n const displayImage = previewUrl || originalImage || undefined;\n\n const footerContent = (\n <div className=\"ermis-channel-info__edit-footer-buttons\">\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--cancel\"\n onClick={onClose}\n disabled={isSaving}\n >\n {cancelLabel}\n </button>\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--save\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? savingLabel : saveLabel}\n </button>\n </div>\n );\n\n return (\n <Modal\n isOpen={true}\n onClose={isSaving ? () => {} : onClose}\n title={title}\n footer={footerContent}\n maxWidth=\"420px\"\n >\n <div className=\"ermis-channel-info__edit-body\">\n {/* Avatar section */}\n <div className=\"ermis-channel-info__edit-avatar-section\">\n <div className=\"ermis-channel-info__edit-avatar-wrap\" onClick={handleAvatarClick}>\n <AvatarComponent image={displayImage} name={name || originalName} size={80} />\n <div className=\"ermis-channel-info__edit-avatar-overlay\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\" />\n <circle cx=\"12\" cy=\"13\" r=\"4\" />\n </svg>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__edit-avatar-btn\"\n onClick={handleAvatarClick}\n type=\"button\"\n disabled={isSaving}\n >\n {changeAvatarLabel}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={imageAccept}\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n />\n </div>\n\n {/* Name field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{nameLabel}</label>\n <input\n className=\"ermis-channel-info__edit-input\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n />\n </div>\n\n {/* Description field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-channel-info__edit-textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n />\n </div>\n\n {/* Public toggle — only for team channels */}\n {isTeamOrMeetingChannel && (\n <div className=\"ermis-channel-info__edit-field ermis-channel-info__edit-field--toggle\">\n <label className=\"ermis-channel-info__edit-label\">{publicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-channel-info__edit-toggle ${isPublic ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isSaving}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"ermis-channel-info__edit-error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nEditChannelModal.displayName = 'EditChannelModal';\n","import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap, formatRelativeDate } from '../../utils';\nimport { Avatar } from '../Avatar';\nimport { Panel } from '../Panel';\nimport type { AvatarProps, SearchResultMessage, MessageSearchPanelProps } from '../../types';\n\n/* ----------------------------------------------------------\n Highlight utility (Accent-insensitive)\n ---------------------------------------------------------- */\nconst removeAccents = (str: string) => str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\n\nconst HighlightedText: React.FC<{ text: string; term: string }> = React.memo(({ text, term }) => {\n if (!term.trim()) return <>{text}</>;\n\n const cleanTerm = removeAccents(term).toLowerCase();\n if (!cleanTerm) return <>{text}</>;\n\n const parts = [];\n let currentIndex = 0;\n const cleanText = removeAccents(text).toLowerCase();\n\n while (true) {\n const startMatch = cleanText.indexOf(cleanTerm, currentIndex);\n if (startMatch === -1) {\n if (currentIndex < text.length) {\n parts.push(<span key={currentIndex}>{text.slice(currentIndex)}</span>);\n }\n break;\n }\n\n if (startMatch > currentIndex) {\n parts.push(<span key={`text-${currentIndex}`}>{text.slice(currentIndex, startMatch)}</span>);\n }\n\n const endMatch = startMatch + cleanTerm.length;\n parts.push(\n <mark key={`mark-${startMatch}`} className=\"ermis-search-panel__highlight\">\n {text.slice(startMatch, endMatch)}\n </mark>\n );\n\n currentIndex = endMatch;\n }\n\n return <>{parts.length > 0 ? parts : text}</>;\n});\nHighlightedText.displayName = 'HighlightedText';\n\n/* ----------------------------------------------------------\n MessageSearchPanel\n ---------------------------------------------------------- */\nexport const MessageSearchPanel: React.FC<MessageSearchPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n AvatarComponent = Avatar,\n placeholder = 'Search messages...',\n title = 'Search Messages',\n emptyText = 'No messages found',\n loadingText = 'Searching...',\n debounceMs = 500,\n}) => {\n const { setJumpToMessageId } = useChatClient();\n\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResultMessage[]>([]);\n const [loading, setLoading] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const offsetRef = useRef(0);\n const queryRef = useRef('');\n\n // Reset all state when the channel changes (or panel closes)\n useEffect(() => {\n setQuery('');\n setResults([]);\n setLoading(false);\n setHasMore(false);\n setLoadingMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n }, [channel?.cid, isOpen]);\n\n // Auto-focus the input when panel opens\n useEffect(() => {\n if (isOpen) {\n setTimeout(() => inputRef.current?.focus(), 300);\n }\n }, [isOpen]);\n\n // Debounced search\n const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setQuery(value);\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n\n if (!value.trim()) {\n setResults([]);\n setLoading(false);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n return;\n }\n\n setLoading(true);\n\n debounceRef.current = setTimeout(async () => {\n queryRef.current = value;\n offsetRef.current = 0;\n\n try {\n const response = await channel.searchMessage(value, 0);\n // Only apply if this is still the latest query\n if (queryRef.current !== value) return;\n\n if (!response) {\n setResults([]);\n setHasMore(false);\n } else {\n setResults(response.messages || []);\n setHasMore((response.messages?.length || 0) >= 25);\n }\n } catch (err) {\n console.error('Search failed:', err);\n setResults([]);\n setHasMore(false);\n } finally {\n setLoading(false);\n }\n }, debounceMs);\n }, [channel, debounceMs]);\n\n // Infinite scroll: load more results\n const handleLoadMore = useCallback(async () => {\n if (loadingMore || !hasMore || !queryRef.current) return;\n\n setLoadingMore(true);\n const nextOffset = offsetRef.current + 25; // offset skips records, limit is 25\n\n try {\n const response = await channel.searchMessage(queryRef.current, nextOffset);\n\n if (!response || !response.messages?.length) {\n setHasMore(false);\n } else {\n offsetRef.current = nextOffset;\n setResults((prev) => [...prev, ...response.messages]);\n setHasMore(response.messages.length >= 25);\n }\n } catch (err) {\n console.error('Load more search results failed:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [channel, hasMore, loadingMore]);\n\n // Scroll handler for infinite scroll\n const handleScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const threshold = 100;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - threshold) {\n handleLoadMore();\n }\n }, [handleLoadMore]);\n\n // Click a result -> jump to that message\n const handleResultClick = useCallback((messageId: string) => {\n setJumpToMessageId(messageId);\n }, [setJumpToMessageId]);\n\n // Derived userMap for resolving mentions, with a lowercase variant for fast lookup\n const userMaps = useMemo(() => {\n const original = buildUserMap(channel.state);\n const lower: typeof original = {};\n for (const [id, name] of Object.entries(original)) {\n lower[id.toLowerCase()] = name;\n }\n return { original, lower };\n }, [channel.state]);\n\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-search-panel\">\n {/* Search Input now inside body */}\n <div className=\"ermis-search-panel__search-box\">\n <div className=\"ermis-search-panel__input-wrap\">\n <svg className=\"ermis-search-panel__input-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n ref={inputRef}\n className=\"ermis-search-panel__input\"\n type=\"text\"\n value={query}\n onChange={handleInputChange}\n placeholder={placeholder}\n />\n {query && (\n <button\n className=\"ermis-search-panel__input-clear\"\n onClick={() => {\n setQuery('');\n setResults([]);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n inputRef.current?.focus();\n }}\n aria-label=\"Clear\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n <div\n ref={scrollRef}\n className=\"ermis-search-panel__results\"\n onScroll={handleScroll}\n >\n {/* Initial state — no query yet */}\n {!query.trim() && !loading && results.length === 0 && (\n <div className=\"ermis-search-panel__idle\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <span>{placeholder}</span>\n </div>\n )}\n\n {/* Loading state */}\n {loading && (\n <div className=\"ermis-search-panel__loading\">\n <div className=\"ermis-search-panel__spinner\" />\n <span>{loadingText}</span>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && query.trim() && results.length === 0 && (\n <div className=\"ermis-search-panel__empty\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Results */}\n {!loading && results.map((msg) => {\n let parsedText = '';\n if (msg.text) {\n // Try standard replacement first\n parsedText = replaceMentionsForPreview(msg.text, msg as any, userMaps.original);\n // Fallback: search API may omit mentioned_users array, so we map @0x IDs efficiently\n if (/@0x[a-fA-F0-9]+/i.test(parsedText)) {\n parsedText = parsedText.replace(/@0x[a-fA-F0-9]+/gi, (match) => {\n const matchedId = match.slice(1).toLowerCase();\n return userMaps.lower[matchedId] ? `@${userMaps.lower[matchedId]}` : match;\n });\n }\n }\n\n return (\n <div\n key={msg.id}\n role=\"button\"\n tabIndex={0}\n className=\"ermis-search-panel__result-item\"\n onClick={() => handleResultClick(msg.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleResultClick(msg.id);\n }\n }}\n >\n <AvatarComponent\n image={msg.user?.avatar || msg.user?.image || msg.user?.avatar_url}\n name={msg.user?.name || msg.user_id}\n size={36}\n />\n <div className=\"ermis-search-panel__result-body\">\n <div className=\"ermis-search-panel__result-meta\">\n <span className=\"ermis-search-panel__result-name\">\n {msg.user?.name || msg.user_id || 'Unknown'}\n </span>\n <span className=\"ermis-search-panel__result-time\">\n {msg.created_at ? formatRelativeDate(msg.created_at) : ''}\n </span>\n </div>\n <p className=\"ermis-search-panel__result-text\">\n {parsedText ? (\n <HighlightedText text={parsedText} term={query} />\n ) : (\n <em>Attachment</em>\n )}\n </p>\n </div>\n </div>\n );\n })}\n\n {/* End of results indicator */}\n {!loading && !loadingMore && !hasMore && results.length > 0 && query.trim() && (\n <div className=\"ermis-search-panel__end-indicator\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Loading more indicator */}\n {loadingMore && (\n <div className=\"ermis-search-panel__loading-more\">\n <div className=\"ermis-search-panel__spinner ermis-search-panel__spinner--small\" />\n </div>\n )}\n </div>\n </Panel>\n );\n});\nMessageSearchPanel.displayName = 'MessageSearchPanel';\n","import React, { useEffect, useRef } from 'react';\n\nexport type PanelProps = {\n /** Whether the panel is visible */\n isOpen: boolean;\n /** Called when user clicks the back button */\n onClose: () => void;\n /** Panel title shown in the header */\n title?: string;\n /** Panel body content */\n children: React.ReactNode;\n /** Optional header content (replaces default title + back button) */\n headerContent?: React.ReactNode;\n /** Additional CSS class name */\n className?: string;\n};\n\n/**\n * Reusable sliding panel component.\n * Slides in from the right to overlay itself on whatever container it's placed in.\n * Use it like a Modal but inside a sidebar — call `isOpen` to show/hide.\n */\nexport const Panel: React.FC<PanelProps> = React.memo(({\n isOpen,\n onClose,\n title,\n children,\n headerContent,\n className,\n}) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n // Focus trap: focus the panel when it opens for accessibility\n useEffect(() => {\n if (isOpen && panelRef.current) {\n panelRef.current.focus();\n }\n }, [isOpen]);\n\n return (\n <div\n ref={panelRef}\n className={`ermis-panel${isOpen ? ' ermis-panel--open' : ''}${className ? ` ${className}` : ''}`}\n tabIndex={-1}\n >\n {headerContent ? (\n headerContent\n ) : (\n <div className=\"ermis-panel__header\">\n <button className=\"ermis-panel__back\" onClick={onClose} aria-label=\"Back\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n {title && <h3 className=\"ermis-panel__title\">{title}</h3>}\n </div>\n )}\n <div className=\"ermis-panel__body\">\n {children}\n </div>\n </div>\n );\n});\nPanel.displayName = 'Panel';\n","import React, { useState, useEffect } from 'react';\nimport { Panel } from '../Panel';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport type { ChannelSettingsPanelProps } from '../../types';\nimport { isGroupChannel } from '../../channelTypeUtils';\nimport { CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const ChannelSettingsPanel: React.FC<ChannelSettingsPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n title = 'Channel Settings',\n slowModeOptions = [\n { label: 'Off', value: 0 },\n { label: '10s', value: 10000 },\n { label: '30s', value: 30000 },\n { label: '1m', value: 60000 },\n { label: '5m', value: 300000 },\n { label: '15m', value: 900000 },\n { label: '1h', value: 3600000 },\n ],\n workspaceTopicsTitle = 'Workspace Topics',\n topicsFeatureName = 'Topics',\n topicsFeatureDescription = 'Enable sub-channels and discussions',\n}) => {\n // Config state\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const isOwner = currentUserRole === CHANNEL_ROLES.OWNER;\n\n const [slowMode, setSlowMode] = useState<number>(0);\n const [topicsEnabled, setTopicsEnabled] = useState<boolean>(false);\n const [capabilities, setCapabilities] = useState<Record<string, boolean>>({\n 'send-message': true,\n 'send-links': true,\n 'update-own-message': true,\n 'delete-own-message': true,\n 'send-reaction': true,\n 'pin-message': true,\n 'create-poll': true,\n 'vote-poll': true,\n });\n\n const [keywords, setKeywords] = useState<string[]>([]);\n const [newKeyword, setNewKeyword] = useState('');\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Sync state when panel opens or channel updates\n useEffect(() => {\n if (!channel) return;\n\n const syncData = (dataToSync = channel.data) => {\n console.log('---syncData---', dataToSync);\n setSlowMode((dataToSync?.member_message_cooldown as number) || 0);\n setKeywords((dataToSync?.filter_words as string[]) || []);\n setTopicsEnabled(dataToSync?.topics_enabled === true);\n\n const caps = dataToSync?.member_capabilities as string[] || [];\n setCapabilities({\n 'send-message': caps.includes('send-message'),\n 'send-links': caps.includes('send-links'),\n 'update-own-message': caps.includes('update-own-message'),\n 'delete-own-message': caps.includes('delete-own-message'),\n 'send-reaction': caps.includes('send-reaction'),\n 'pin-message': caps.includes('pin-message'),\n 'create-poll': caps.includes('create-poll'),\n 'vote-poll': caps.includes('vote-poll'),\n });\n setError(null);\n };\n\n if (isOpen) {\n syncData();\n }\n\n // Listen to real-time changes\n const subscription = channel.on('channel.updated', (event: any) => {\n const latestData = event?.channel || channel.data;\n // Force mutating local channel.data to ensure future syncData hits cache\n if (event?.channel && channel.data) {\n Object.assign(channel.data, event.channel);\n }\n\n if (isOpen) {\n syncData(latestData);\n }\n });\n\n return () => {\n subscription?.unsubscribe();\n };\n }, [isOpen, channel]);\n\n const toggleCapability = (key: string) => {\n setCapabilities(prev => ({ ...prev, [key]: !prev[key] }));\n };\n\n // Compute dirty state\n const isSlowModeChanged = slowMode !== ((channel?.data?.member_message_cooldown as number) || 0);\n const isTopicsChanged = topicsEnabled !== (channel?.data?.topics_enabled === true);\n\n const currentKeywordsSorted = [...keywords].sort().join(',');\n const originalKeywordsSorted = [...((channel?.data?.filter_words as string[]) || [])].sort().join(',');\n const isKeywordsChanged = currentKeywordsSorted !== originalKeywordsSorted;\n\n const originalCapabilities = channel?.data?.member_capabilities as string[] || [];\n const initialCapabilities: Record<string, boolean> = {\n 'send-message': originalCapabilities.includes('send-message'),\n 'send-links': originalCapabilities.includes('send-links'),\n 'update-own-message': originalCapabilities.includes('update-own-message'),\n 'delete-own-message': originalCapabilities.includes('delete-own-message'),\n 'send-reaction': originalCapabilities.includes('send-reaction'),\n 'pin-message': originalCapabilities.includes('pin-message'),\n 'create-poll': originalCapabilities.includes('create-poll'),\n 'vote-poll': originalCapabilities.includes('vote-poll'),\n };\n const isCapabilitiesChanged = Object.keys(capabilities).some(k => capabilities[k] !== initialCapabilities[k]);\n\n const isDirty = isSlowModeChanged || isKeywordsChanged || isCapabilitiesChanged || isTopicsChanged;\n\n const handleAddNewKeyword = () => {\n if (newKeyword.trim()) {\n const keyword = newKeyword.trim().toLowerCase();\n if (!keywords.includes(keyword)) {\n setKeywords(prev => [...prev, keyword]);\n }\n setNewKeyword('');\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleAddNewKeyword();\n }\n };\n\n const handeRemoveKeyword = (kw: string) => {\n setKeywords(prev => prev.filter(k => k !== kw));\n };\n\n const handleSave = async () => {\n if (!channel) return;\n setIsSaving(true);\n setError(null);\n try {\n const dataUpdates: any = {};\n let capabilitiesArray: string[] | null = null;\n\n if (isSlowModeChanged) {\n dataUpdates.member_message_cooldown = slowMode;\n }\n\n if (isKeywordsChanged) {\n dataUpdates.filter_words = keywords;\n }\n\n if (isCapabilitiesChanged) {\n const controlledKeys = Object.keys(capabilities);\n const originalCaps = (channel.data?.member_capabilities as string[]) || [];\n\n // Preserve unmanaged original capabilities (e.g. create-call, join-call)\n const unmanagedCaps = originalCaps.filter(c => !controlledKeys.includes(c));\n\n // Extract managed capabilities that are currently enabled (true)\n const managedEnabledCaps = controlledKeys.filter(k => capabilities[k as keyof typeof capabilities]);\n\n // Merge into the final payload array\n capabilitiesArray = [...unmanagedCaps, ...managedEnabledCaps];\n }\n\n if (Object.keys(dataUpdates).length > 0 || capabilitiesArray !== null) {\n const payload: any = {};\n\n if (Object.keys(dataUpdates).length > 0) {\n payload.data = dataUpdates;\n if (channel.data) Object.assign(channel.data, dataUpdates);\n }\n\n if (capabilitiesArray !== null) {\n payload.capabilities = capabilitiesArray;\n if (channel.data) {\n // Local fallback naming to keep UI synchronous\n channel.data.member_capabilities = capabilitiesArray;\n }\n }\n\n // Use _update instead of update to safely construct root-level payloads\n await (channel as any)._update(payload);\n }\n\n if (isTopicsChanged) {\n if (topicsEnabled) {\n await channel.enableTopics();\n } else {\n await channel.disableTopics();\n }\n }\n\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update settings');\n } finally {\n setIsSaving(false);\n }\n };\n\n // We do NOT return null based on !isOpen so the sliding CSS transition is preserved.\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-settings-panel\">\n\n {/* \n This wrapper creates a neat scrollable area with subtle gray background\n which makes white cards pop out smoothly.\n */}\n <div\n className=\"ermis-settings-panel__body\"\n style={{\n flex: 1,\n minHeight: 0,\n padding: '16px',\n overflowY: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '16px',\n background: 'var(--ermis-bg-secondary)'\n }}\n >\n\n {/* Section 1: Permissions */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-primary-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-primary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" />\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Member Permissions\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Slow Mode\n </label>\n <div style={{ position: 'relative' }}>\n <select\n value={slowMode}\n onChange={e => setSlowMode(Number(e.target.value))}\n style={{\n width: '100%',\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n fontWeight: 500,\n appearance: 'none',\n outline: 'none',\n cursor: isSaving ? 'not-allowed' : 'pointer',\n transition: 'border-color 0.2s'\n }}\n disabled={isSaving}\n >\n {slowModeOptions.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n <div style={{ position: 'absolute', right: '14px', top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: 'var(--ermis-text-secondary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Capabilities\n </label>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n {Object.entries(capabilities).map(([key, value], index, arr) => (\n <div\n key={key}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n borderBottom: index < arr.length - 1 ? '1px solid var(--ermis-border-color)' : 'none'\n }}\n >\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {key.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}\n </span>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n className={`ermis-channel-info__edit-toggle ${value ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => toggleCapability(key)}\n disabled={isSaving}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n ))}\n </div>\n </div>\n </section>\n\n {/* Section 2: Content Moderation */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-danger-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-danger)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path>\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Content Moderation\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Keyword Filtering\n </label>\n <div style={{ display: 'flex', gap: '8px', position: 'relative' }}>\n <input\n type=\"text\"\n value={newKeyword}\n onChange={e => setNewKeyword(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type keyword and press Enter or Add...\"\n style={{\n flex: 1,\n minWidth: 0,\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n outline: 'none'\n }}\n disabled={isSaving}\n />\n <button\n type=\"button\"\n onClick={handleAddNewKeyword}\n disabled={isSaving || !newKeyword.trim()}\n style={{\n padding: '0 12px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary-light)',\n color: 'var(--ermis-color-primary)',\n border: 'none',\n fontWeight: 600,\n fontSize: '13px',\n cursor: isSaving || !newKeyword.trim() ? 'not-allowed' : 'pointer',\n opacity: isSaving || !newKeyword.trim() ? 0.6 : 1,\n transition: 'opacity 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center'\n }}\n >\n Add\n </button>\n </div>\n </div>\n\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', minHeight: '32px' }}>\n {keywords.map(kw => (\n <span\n key={kw}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n padding: '3px 8px',\n borderRadius: '16px',\n background: 'var(--ermis-color-danger-light)',\n color: 'var(--ermis-color-danger)',\n border: '1px solid rgba(239, 68, 68, 0.2)',\n fontSize: '12px',\n fontWeight: 600\n }}\n >\n {kw}\n <button\n onClick={() => handeRemoveKeyword(kw)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'transparent',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n color: 'inherit',\n opacity: 0.8,\n }}\n disabled={isSaving}\n aria-label=\"Remove keyword\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </span>\n ))}\n {keywords.length === 0 && (\n <span style={{ fontSize: '14px', color: 'var(--ermis-text-secondary)', padding: '6px 0', fontStyle: 'italic' }}>\n No blacklisted keywords added.\n </span>\n )}\n </div>\n </section>\n\n {/* Section 3: Features */}\n {isGroupChannel(channel) && (\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'rgba(168, 85, 247, 0.1)', padding: '4px', borderRadius: '8px', color: '#a855f7' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"12 2 2 7 12 12 22 7 12 2\"></polygon>\n <polyline points=\"2 17 12 22 22 17\"></polyline>\n <polyline points=\"2 12 12 17 22 12\"></polyline>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n {workspaceTopicsTitle}\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n }}\n >\n <div style={{ display: 'flex', flexDirection: 'column' }}>\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {topicsFeatureName}\n </span>\n <span style={{ fontSize: '12px', color: 'var(--ermis-text-secondary)', marginTop: '2px' }}>\n {topicsFeatureDescription}\n </span>\n {!isOwner && (\n <span style={{ fontSize: '11px', color: 'var(--ermis-color-danger)', marginTop: '4px', fontWeight: 500 }}>\n Only channel owner can change this.\n </span>\n )}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={topicsEnabled}\n className={`ermis-channel-info__edit-toggle ${topicsEnabled ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => isOwner && setTopicsEnabled(!topicsEnabled)}\n disabled={isSaving || !isOwner}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center', cursor: (!isOwner || isSaving) ? 'not-allowed' : 'pointer' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n </div>\n </div>\n </section>\n )}\n\n\n </div>\n\n {/* Footer Area */}\n <div\n className=\"ermis-settings-panel__footer\"\n style={{\n flexShrink: 0,\n padding: '12px 16px',\n background: 'var(--ermis-bg-primary)',\n borderTop: '1px solid var(--ermis-border-color)',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px'\n }}\n >\n {error && (\n <div style={{ color: 'var(--ermis-color-danger)', fontSize: '13px', display: 'flex', alignItems: 'center', gap: '6px', fontWeight: 500 }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" /><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" /></svg>\n {error}\n </div>\n )}\n <button\n onClick={handleSave}\n disabled={isSaving || !isDirty}\n style={{\n width: '100%',\n padding: '10px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary, #006eff)',\n color: '#ffffff',\n border: 'none',\n fontSize: '14px',\n fontWeight: 600,\n cursor: (isSaving || !isDirty) ? 'not-allowed' : 'pointer',\n opacity: (isSaving || !isDirty) ? 0.6 : 1,\n transition: 'all 0.2s ease',\n boxShadow: (isSaving || !isDirty) ? 'none' : '0 4px 12px rgba(0, 110, 255, 0.2)'\n }}\n >\n {isSaving ? (\n <span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}>\n <svg className=\"ermis-spinner\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n </svg>\n Saving...\n </span>\n ) : 'Save Updates'}\n </button>\n </div>\n\n </Panel>\n );\n});\n\nChannelSettingsPanel.displayName = 'ChannelSettingsPanel';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal } from './Modal';\nimport { UserPicker } from './UserPicker';\nimport { Avatar } from './Avatar';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { CreateChannelModalProps, UserPickerUser } from '../types';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n\nexport const CreateChannelModal: React.FC<CreateChannelModalProps> = ({\n isOpen,\n onClose,\n onSuccess,\n AvatarComponent = Avatar,\n UserItemComponent,\n title = 'New Message',\n directTabLabel = 'Direct',\n groupTabLabel = 'Group',\n groupNameLabel = 'Channel Name',\n groupNamePlaceholder = 'Enter channel name (required)',\n groupDescriptionLabel = 'Description',\n groupDescriptionPlaceholder = 'Optional description',\n groupPublicLabel = 'Public Channel',\n userSearchPlaceholder = 'Search users...',\n cancelButtonLabel = 'Cancel',\n createButtonLabel = 'Create',\n creatingButtonLabel = 'Creating...',\n messageButtonLabel = 'Message',\n}) => {\n const { client, setActiveChannel } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [tab, setTab] = useState<'messaging' | 'team'>('messaging');\n const [step, setStep] = useState<1 | 2>(1); // Only for team channel\n\n // Group specific\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [isPublic, setIsPublic] = useState(false);\n\n // Users\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n\n // Progress/Error\n const [isCreating, setIsCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /* ---------- Exclude IDs for Direct ---------- */\n const hasExistingDirectChannel = useMemo(() => {\n if (!client || !currentUserId || tab !== 'messaging' || selectedUsers.length === 0) return false;\n const targetUserId = selectedUsers[0].id;\n\n return Object.values(client.activeChannels).some((ch: any) => {\n if (isDirectChannel(ch) && ch.state?.members) {\n const membersList = Object.keys(ch.state.members);\n return membersList.length === 2 && \n membersList.includes(currentUserId) && \n membersList.includes(targetUserId);\n }\n return false;\n });\n }, [client, currentUserId, tab, selectedUsers]);\n\n /* ---------- Handlers ---------- */\n const handleCreate = useCallback(async () => {\n if (!client || !currentUserId || isCreating) return;\n\n // Validations\n if (selectedUsers.length === 0) {\n setError('Please select at least one user.');\n return;\n }\n\n if (tab === 'team' && !name.trim()) {\n setError('Group name is required.');\n return;\n }\n\n setIsCreating(true);\n setError(null);\n\n try {\n let createdChannel;\n\n if (tab === 'messaging') {\n const targetUserId = selectedUsers[0].id;\n\n // Try to find an existing direct channel locally\n const existingChannel = Object.values(client.activeChannels).find((ch: any) => {\n if (isDirectChannel(ch) && ch.state?.members) {\n const membersList = Object.keys(ch.state.members);\n return membersList.length === 2 && \n membersList.includes(currentUserId) && \n membersList.includes(targetUserId);\n }\n return false;\n });\n\n if (existingChannel) {\n if (setActiveChannel) setActiveChannel(existingChannel as any);\n if (onSuccess) {\n onSuccess(existingChannel as any);\n } else {\n onClose();\n }\n setIsCreating(false);\n return;\n }\n\n createdChannel = client.channel('messaging', {\n members: [currentUserId, targetUserId],\n } as any);\n const response = (await createdChannel.create()) as any;\n if (response?.channel?.id) {\n createdChannel = client.channel('messaging', response.channel.id);\n await createdChannel.watch();\n }\n } else {\n // Group Channel\n const memberIds = selectedUsers.map(member => member.id);\n // Ensure current user is in the group members\n if (!memberIds.includes(currentUserId)) {\n memberIds.push(currentUserId);\n }\n\n const payload: any = {\n name: name.trim(),\n members: memberIds,\n public: isPublic,\n };\n\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n createdChannel = client.channel('team', payload);\n const response = (await createdChannel.create()) as any;\n if (response?.channel?.id) {\n createdChannel = client.channel('team', response.channel.id);\n await createdChannel.watch();\n }\n }\n\n if (setActiveChannel) {\n setActiveChannel(createdChannel);\n }\n\n // Cleanup and execute callback\n if (onSuccess) {\n onSuccess(createdChannel);\n } else {\n onClose();\n }\n\n } catch (err: any) {\n setError(err?.message || 'Failed to create channel');\n } finally {\n setIsCreating(false);\n }\n }, [client, currentUserId, isCreating, selectedUsers, tab, name, isPublic, description, onSuccess, onClose]);\n\n\n const isValid = useMemo(() => {\n if (tab === 'messaging' && selectedUsers.length === 0) return false;\n if (tab === 'team' && step === 1 && !name.trim()) return false;\n if (tab === 'team' && step === 2 && selectedUsers.length === 0) return false;\n return true;\n }, [selectedUsers, tab, name, step]);\n\n let footer;\n if (tab === 'messaging') {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : (hasExistingDirectChannel ? messageButtonLabel : createButtonLabel)}\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 1) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={() => { setError(null); setStep(2); }} disabled={isCreating || !isValid}>\n Next\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 2) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={() => { setError(null); setStep(1); }} disabled={isCreating}>Back</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : createButtonLabel}\n </button>\n </div>\n );\n }\n\n return (\n <Modal isOpen={isOpen} onClose={isCreating ? () => { } : onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <div className=\"ermis-create-channel__body\">\n\n {/* Type Toggle */}\n <div className=\"ermis-create-channel__tabs\">\n <button\n className={`ermis-create-channel__tab ${tab === 'messaging' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('messaging');\n setStep(1);\n setSelectedUsers([]);\n setError(null);\n }}\n disabled={isCreating}\n >\n {directTabLabel}\n </button>\n <button\n className={`ermis-create-channel__tab ${tab === 'team' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('team');\n setStep(1);\n setSelectedUsers([]);\n setError(null);\n }}\n disabled={isCreating}\n >\n {groupTabLabel}\n </button>\n </div>\n\n {/* Group Specific Fields - Step 1 */}\n {tab === 'team' && step === 1 && (\n <>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupNameLabel} <span style={{ color: 'var(--ermis-error)' }}>*</span></label>\n <input\n className=\"ermis-create-channel__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={groupNamePlaceholder}\n disabled={isCreating}\n maxLength={100}\n />\n </div>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupDescriptionLabel}</label>\n <textarea\n className=\"ermis-create-channel__textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={groupDescriptionPlaceholder}\n disabled={isCreating}\n maxLength={500}\n rows={2}\n />\n </div>\n\n <div className=\"ermis-create-channel__field ermis-create-channel__field--toggle\">\n <label className=\"ermis-create-channel__label\">{groupPublicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-create-channel__toggle ${isPublic ? 'ermis-create-channel__toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isCreating}\n >\n <span className=\"ermis-create-channel__toggle-thumb\" />\n </button>\n </div>\n </>\n )}\n\n {/* User Selection - Step 2 (Group) or Step 1 (Messaging) */}\n {((tab === 'team' && step === 2) || tab === 'messaging') && (\n <div className=\"ermis-create-channel__users\">\n <div className=\"ermis-create-channel__users-title\">\n Members <span style={{ color: 'var(--ermis-error)' }}>*</span>\n </div>\n <div style={{ height: tab === 'team' ? '280px' : '400px', display: 'flex', flexDirection: 'column' }}>\n <UserPicker\n mode={tab === 'messaging' ? 'radio' : 'checkbox'}\n onSelectionChange={setSelectedUsers}\n initialSelectedUsers={selectedUsers}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n searchPlaceholder={userSearchPlaceholder}\n />\n </div>\n </div>\n )}\n\n {error && (\n <div className=\"ermis-create-channel__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n\n </div>\n </Modal>\n );\n};\n"],"mappings":"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","names":["useState","useCallback","React","useEffect","useRef","useState","useCallback","useEffect","jsx","React","useMemo","useState","React","useState","useEffect","useCallback","useRef","useContext","useContext","jsx","jsxs","React","useState","useRef","useEffect","useCallback","jsx","jsxs","React","useState","useMemo","CallStatus","Fragment","jsx","jsxs","React","useRef","useState","useCallback","useEffect","jsx","jsxs","useState","useCallback","useState","useState","useEffect","useRef","useRef","useEffect","ch","useEffect","useState","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useMemo","useMemo","useState","useEffect","useState","useEffect","useMemo","useRef","useMemo","useState","useRef","useEffect","useState","useEffect","useState","useEffect","React","useEffect","useState","useCallback","useMemo","React","useState","useCallback","jsx","jsxs","React","useState","useCallback","React","useState","useCallback","useEffect","useRef","jsx","Fragment","jsx","jsxs","hasTopicsEnabled","React","useState","useCallback","jsx","jsxs","React","useState","useEffect","useMemo","useCallback","image","React","useEffect","useMemo","useState","React","useState","useEffect","useCallback","useMemo","useRef","Fragment","jsx","jsxs","React","useState","useRef","useMemo","useCallback","useEffect","jsx","jsxs","DefaultEmpty","React","useState","useEffect","useMemo","React","useMemo","useState","useEffect","useContext","Fragment","jsx","jsxs","React","useContext","useState","useEffect","useMemo","React","useRef","useCallback","useMemo","useEffect","VList","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","useState","useEffect","useCallback","useRef","formatMessage","useState","useRef","useEffect","useCallback","formatMessage","useEffect","useCallback","useCallback","useEffect","client","useState","useEffect","useMemo","React","React","useMemo","jsx","jsxs","React","useMemo","React","useCallback","useMemo","useState","useEffect","useCallback","useState","useEffect","useCallback","useMemo","Fragment","jsx","jsxs","React","useCallback","jsxs","Fragment","jsx","React","jsx","jsxs","React","React","useCallback","jsx","React","useCallback","jsx","jsxs","React","React","useState","useMemo","useCallback","parseSystemMessage","parseSignalMessage","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useMemo","useCallback","parseSystemMessage","parseSignalMessage","React","useState","useEffect","useMemo","useCallback","jsx","jsxs","React","useMemo","useState","useEffect","useCallback","React","jsx","jsxs","React","React","useState","useEffect","useRef","useState","useRef","useEffect","Fragment","jsx","jsxs","React","React","jsx","jsxs","React","jsx","jsxs","React","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","React","DefaultEmpty","useRef","useMemo","useCallback","useEffect","VList","React","useState","useCallback","useMemo","useEffect","useRef","useState","useCallback","useMemo","useState","useMemo","useCallback","useState","useCallback","useRef","useState","useCallback","useRef","useState","useRef","useCallback","useState","useCallback","useRef","React","jsx","React","useEffect","useRef","VList","jsx","jsxs","React","useRef","useEffect","VList","React","isHeicFile","jsx","jsxs","formatFileSize","getFileIcon","isImage","isVideo","React","useMemo","jsx","jsxs","MAX_PREVIEW_LENGTH","truncateText","React","useMemo","React","useMemo","jsx","jsxs","MAX_PREVIEW_LENGTH","truncateText","getAttachmentSummary","React","useMemo","Fragment","jsx","jsxs","React","useState","useEffect","useRef","useCallback","useMemo","React","useState","useCallback","React","useState","useEffect","useMemo","useCallback","useDeferredValue","VList","React","useState","useMemo","jsx","jsxs","React","useState","useMemo","isVideo","React","useState","useMemo","jsx","jsxs","React","useState","useMemo","React","jsx","jsxs","React","React","useState","Fragment","jsx","jsxs","React","useState","React","jsx","jsxs","jsx","jsxs","React","useMemo","useState","useDeferredValue","useEffect","useCallback","VList","useState","useMemo","useCallback","React","useState","useEffect","useMemo","useCallback","useRef","VList","jsx","jsxs","React","useCallback","useState","useRef","useMemo","useEffect","jsx","useState","useMemo","useCallback","React","useState","useRef","useCallback","useEffect","jsx","jsxs","React","useState","useRef","useEffect","useCallback","React","useState","useEffect","useRef","useCallback","useMemo","React","useEffect","useRef","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useRef","useEffect","useCallback","useMemo","React","useState","useEffect","jsx","jsxs","React","useState","useEffect","Fragment","jsx","jsxs","React","useCallback","useState","useState","useMemo","useCallback","Fragment","jsx","jsxs","useState","useMemo","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/context/ChatProvider.tsx","../src/components/ErmisCallProvider.tsx","../src/context/ErmisCallContext.tsx","../src/components/ErmisCallUI.tsx","../src/hooks/useCallContext.ts","../src/components/Modal.tsx","../src/components/Avatar.tsx","../src/components/MediaLightbox.tsx","../src/utils.ts","../src/messageTypeUtils.ts","../src/hooks/useDownloadHandler.ts","../src/hooks/useChatClient.ts","../src/utils/avatarColors.ts","../src/context/ChatComponentsContext.tsx","../src/hooks/useChatUser.ts","../src/hooks/useInviteChannels.ts","../src/channelTypeUtils.ts","../src/channelRoleUtils.ts","../src/hooks/useContactChannels.ts","../src/hooks/useInviteCount.ts","../src/hooks/useContactCount.ts","../src/hooks/useChannel.ts","../src/hooks/useChannelListUpdates.ts","../src/hooks/useChannelRowUpdates.ts","../src/hooks/useBannedState.ts","../src/hooks/useBlockedState.ts","../src/hooks/useOnlineStatus.ts","../src/hooks/useOnlineUsers.ts","../src/hooks/usePendingState.ts","../src/hooks/usePreviewState.ts","../src/hooks/useTopicGroupUpdates.ts","../src/hooks/useDragAndDrop.ts","../src/hooks/useMessageSend.ts","../src/hooks/useFileUpload.ts","../src/hooks/useE2eeFileUpload.ts","../src/hooks/useE2eeAttachmentRenderer.ts","../src/hooks/usePendingE2eeSends.ts","../src/hooks/useEmojiPicker.ts","../src/hooks/useStickerPicker.ts","../src/hooks/useChannelCapabilities.ts","../src/hooks/useChannelData.ts","../src/components/ChannelList.tsx","../src/components/TopicModal.tsx","../src/components/ChannelActions.tsx","../src/components/Dropdown.tsx","../src/components/FlatTopicGroupItem.tsx","../src/components/TopicList.tsx","../src/components/Channel.tsx","../src/components/ForwardMessageModal.tsx","../src/hooks/useForwardMessage.ts","../src/components/ChannelHeader.tsx","../src/components/VirtualMessageList.tsx","../src/hooks/useLoadMessages.ts","../src/hooks/useScrollToMessage.ts","../src/hooks/useChannelMessages.ts","../src/components/MessageItem.tsx","../src/components/QuotedMessagePreview.tsx","../src/components/MessageActionsBox.tsx","../src/hooks/useMessageActions.ts","../src/components/MessageQuickReactions.tsx","../src/components/MessageReactions.tsx","../src/components/MessageRenderers.tsx","../src/components/ChannelInfo/utils.tsx","../src/components/PinnedMessages.tsx","../src/components/ReadReceipts.tsx","../src/components/TypingIndicator.tsx","../src/hooks/useTypingIndicator.ts","../src/components/PendingOverlay.tsx","../src/components/SkippedOverlay.tsx","../src/components/BannedOverlay.tsx","../src/components/ClosedTopicOverlay.tsx","../src/components/MessageInput.tsx","../src/hooks/useMentions.ts","../src/components/MessageInputDefaults.tsx","../src/components/MentionSuggestions.tsx","../src/components/FilesPreview.tsx","../src/components/ReplyPreview.tsx","../src/components/EditPreview.tsx","../src/components/PreviewOverlay.tsx","../src/hooks/useRecoveryPin.ts","../src/components/ChannelInfo/ChannelInfo.tsx","../src/components/ChannelInfo/ChannelInfoTabs.tsx","../src/components/ChannelInfo/useChannelInfoTabs.tsx","../src/components/ChannelInfo/MediaGridItem.tsx","../src/components/ChannelInfo/LinkListItem.tsx","../src/components/ChannelInfo/FileListItem.tsx","../src/components/ChannelInfo/MemberListItem.tsx","../src/components/ChannelInfo/States.tsx","../src/components/ChannelInfo/AddMemberModal.tsx","../src/components/UserPicker.tsx","../src/components/ChannelInfo/EditChannelModal.tsx","../src/components/ChannelInfo/MessageSearchPanel.tsx","../src/components/Panel.tsx","../src/components/ChannelInfo/useMessageSearch.tsx","../src/components/ChannelInfo/ChannelSettingsPanel.tsx","../src/components/ChannelInfo/useChannelSettings.ts","../src/components/CreateChannelModal.tsx","../src/components/RecoveryPin/RecoveryPin.tsx"],"sourcesContent":["import React, { createContext, useState, useCallback, useRef, useMemo } from 'react';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { Theme, ChatContextValue, ChatProviderProps, ReadStateEntry } from '../types';\nimport { ErmisCallProvider } from '../components/ErmisCallProvider';\nimport { ErmisCallUI } from '../components/ErmisCallUI';\nimport { ChatComponentsContext } from './ChatComponentsContext';\n\nexport type { Theme, ChatContextValue, ChatProviderProps } from '../types';\n\nexport const ChatContext = createContext<ChatContextValue | null>(null);\n\nexport const ChatProvider: React.FC<ChatProviderProps> = ({\n client,\n children,\n components = {},\n initialTheme = 'light',\n enableCall = false,\n callSessionId,\n callWasmPath,\n callRelayUrl,\n CallUIComponent,\n incomingCallAudioPath,\n outgoingCallAudioPath,\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [activeChannelRaw, setActiveChannelRaw] = useState<Channel | null>(null);\n const [theme, setTheme] = useState<Theme>(initialTheme);\n const [messages, setMessages] = useState<FormatMessageResponse[]>([]);\n const [quotedMessage, setQuotedMessage] = useState<FormatMessageResponse | null>(null);\n const [editingMessage, setEditingMessage] = useState<FormatMessageResponse | null>(null);\n const [readState, setReadState] = useState<Record<string, ReadStateEntry>>({});\n const [forwardingMessage, setForwardingMessage] = useState<FormatMessageResponse | null>(null);\n const [jumpToMessageId, setJumpToMessageId] = useState<string | null>(null);\n\n const activeChannel = activeChannelRaw;\n const activeChannelCidRef = useRef<string | null>(null);\n\n // In-memory draft storage — Map<cid, { html: string; files: any[] }>\n // O(1) lookup/insert/delete, bounded by number of visited channels per session\n const draftsRef = useRef<Map<string, { html: string; files: any[] }>>(new Map());\n\n const setActiveChannel = useCallback((channel: Channel | null) => {\n const newCid = channel?.cid || null;\n if (activeChannelCidRef.current === newCid) return;\n \n activeChannelCidRef.current = newCid;\n setActiveChannelRaw(channel);\n setQuotedMessage(null);\n setEditingMessage(null);\n setMessages([]);\n setReadState({});\n }, []);\n\n /** Re-read messages from SDK state into React state */\n const syncMessages = useCallback(() => {\n if (activeChannel) {\n setMessages([...activeChannel.state.latestMessages]);\n }\n }, [activeChannel]);\n\n /** Save a draft message (innerHTML and files) for a specific channel */\n const setDraft = useCallback((cid: string, draft: { html: string; files: any[] }) => {\n if ((draft.html && draft.html.trim()) || (draft.files && draft.files.length > 0)) {\n draftsRef.current.set(cid, draft);\n } else {\n draftsRef.current.delete(cid);\n }\n }, []);\n\n /** Retrieve the saved draft for a specific channel */\n const getDraft = useCallback((cid: string): { html: string; files: any[] } | undefined => {\n return draftsRef.current.get(cid);\n }, []);\n\n /** Clear all saved drafts (e.g. on logout) */\n const clearAllDrafts = useCallback(() => {\n draftsRef.current.clear();\n }, []);\n\n const value: ChatContextValue = {\n client,\n activeChannel,\n setActiveChannel,\n theme,\n setTheme,\n messages,\n setMessages,\n syncMessages,\n quotedMessage,\n setQuotedMessage,\n editingMessage,\n setEditingMessage,\n readState,\n setReadState,\n forwardingMessage,\n setForwardingMessage,\n jumpToMessageId,\n setJumpToMessageId,\n enableCall,\n setDraft,\n getDraft,\n clearAllDrafts,\n };\n\n const CallUIView = CallUIComponent ? <CallUIComponent /> : (\n <ErmisCallUI\n incomingCallAudioPath={incomingCallAudioPath}\n outgoingCallAudioPath={outgoingCallAudioPath}\n />\n );\n\n const content = (\n <ChatComponentsContext.Provider value={components}>\n <ChatContext.Provider value={value}>\n <div className={`ermis-chat ermis-chat--${theme}`}>\n {children}\n {enableCall && CallUIView}\n </div>\n </ChatContext.Provider>\n </ChatComponentsContext.Provider>\n );\n\n if (enableCall) {\n if (!callSessionId) {\n console.warn('ErmisChat React: enableCall is true but callSessionId is missing.');\n }\n return (\n <ErmisCallProvider\n client={client}\n sessionId={callSessionId || ''}\n wasmPath={callWasmPath}\n relayUrl={callRelayUrl}\n onCallStart={onCallStart}\n onCallEnd={onCallEnd}\n onCallError={onCallError}\n onIncomingCall={onIncomingCall}\n onCallAccepted={onCallAccepted}\n onCallRejected={onCallRejected}\n >\n {content}\n </ErmisCallProvider>\n );\n }\n\n return content;\n};\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { CallStatus, ErmisCallNode, type UserCallInfo, type CallEventData } from '@ermis-network/ermis-chat-sdk';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport type { ErmisCallProviderProps } from '../types';\n\nexport type { ErmisCallProviderProps } from '../types';\n\nexport const ErmisCallProvider: React.FC<ErmisCallProviderProps> = ({\n children,\n client,\n sessionId,\n wasmPath = '/ermis_call_node_wasm_bg.wasm',\n relayUrl = 'https://iroh-relay.ermis.network:8443',\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [callNode, setCallNode] = useState<ErmisCallNode | null>(null);\n const [callStatus, setCallStatus] = useState<CallStatus | ''>('');\n const [localStream, setLocalStream] = useState<MediaStream | null>(null);\n const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null);\n const [callType, setCallType] = useState<string>('audio');\n const [callerInfo, setCallerInfo] = useState<UserCallInfo | undefined>(undefined);\n const [receiverInfo, setReceiverInfo] = useState<UserCallInfo | undefined>(undefined);\n const [isIncoming, setIsIncoming] = useState<boolean>(false);\n const [isMicMuted, setIsMicMuted] = useState(false);\n const [isVideoMuted, setIsVideoMuted] = useState(true); // Default to true until a video track is added\n const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([]);\n const [videoDevices, setVideoDevices] = useState<MediaDeviceInfo[]>([]);\n const [selectedAudioDeviceId, setSelectedAudioDeviceId] = useState<string>('');\n const [selectedVideoDeviceId, setSelectedVideoDeviceId] = useState<string>('');\n const [isScreenSharing, setIsScreenSharing] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [isRemoteMicMuted, setIsRemoteMicMuted] = useState(false);\n const [isRemoteVideoMuted, setIsRemoteVideoMuted] = useState(false);\n const [isAccepting, setIsAccepting] = useState(false);\n const [isRejecting, setIsRejecting] = useState(false);\n const [isEnding, setIsEnding] = useState(false);\n\n // Call duration timer (C7 — exposed via context)\n const [callDuration, setCallDuration] = useState(0);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const startTimer = useCallback(() => {\n setCallDuration(0);\n timerRef.current = setInterval(() => {\n setCallDuration((prev) => prev + 1);\n }, 1000);\n }, []);\n\n const stopTimer = useCallback(() => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n setCallDuration(0);\n }, []);\n\n useEffect(() => {\n if (callStatus === CallStatus.CONNECTED) {\n startTimer();\n setIsAccepting(false);\n } else {\n stopTimer();\n }\n if (!callStatus) {\n setIsAccepting(false);\n setIsRejecting(false);\n setIsEnding(false);\n }\n return () => stopTimer();\n }, [callStatus, startTimer, stopTimer]);\n\n useEffect(() => {\n if (!client || !sessionId) return;\n\n // Create new call node instance\n const node = new ErmisCallNode(client, sessionId, wasmPath, relayUrl);\n setCallNode(node);\n\n // Register Call Events\n node.onCallEvent = (data: CallEventData) => {\n setIsIncoming(data.type === 'incoming');\n setCallType(data.callType);\n setCallerInfo(data.callerInfo);\n setReceiverInfo(data.receiverInfo);\n // C1: Lifecycle callback — incoming call\n if (data.type === 'incoming' && data.callerInfo) {\n onIncomingCall?.(data.callerInfo);\n }\n };\n\n node.onError = (error: string) => {\n setErrorMessage(error);\n // C1: Lifecycle callback — error\n onCallError?.(error);\n };\n node.onDeviceChange = (audio, video) => {\n setAudioDevices(audio);\n setVideoDevices(video);\n const selected = node.getSelectedDevices();\n if (selected.audioDevice) setSelectedAudioDeviceId(selected.audioDevice.deviceId);\n else if (audio.length > 0) setSelectedAudioDeviceId(audio[0].deviceId);\n \n if (selected.videoDevice) setSelectedVideoDeviceId(selected.videoDevice.deviceId);\n else if (video.length > 0) setSelectedVideoDeviceId(video[0].deviceId);\n };\n\n node.onScreenShareChange = (isSharing: boolean) => setIsScreenSharing(isSharing);\n\n node.getDevices().then(({ audioDevices: a, videoDevices: v }) => {\n setAudioDevices(a);\n setVideoDevices(v);\n const selected = node.getSelectedDevices();\n if (selected.audioDevice) setSelectedAudioDeviceId(selected.audioDevice.deviceId);\n else if (a.length > 0) setSelectedAudioDeviceId(a[0].deviceId);\n \n if (selected.videoDevice) setSelectedVideoDeviceId(selected.videoDevice.deviceId);\n else if (v.length > 0) setSelectedVideoDeviceId(v[0].deviceId);\n });\n\n node.onCallStatus = (status: string | null) => {\n const parsedStatus = status as CallStatus | '';\n setCallStatus(parsedStatus);\n if (parsedStatus === CallStatus.ENDED || !parsedStatus) {\n setLocalStream(null);\n setRemoteStream(null);\n setIsIncoming(false);\n setCallStatus('');\n }\n };\n\n node.onLocalStream = (stream: MediaStream) => {\n setLocalStream(stream);\n const audioTracks = stream.getAudioTracks();\n setIsMicMuted(audioTracks.length === 0 || !audioTracks[0].enabled);\n const videoTracks = stream.getVideoTracks();\n setIsVideoMuted(videoTracks.length === 0 || !videoTracks[0].enabled);\n };\n\n node.onRemoteStream = (stream: MediaStream) => setRemoteStream(stream);\n\n // Listen for remote peer transceiver state via data channel\n node.onDataChannelMessage = (state: { audio_enable?: boolean; video_enable?: boolean }) => {\n if (typeof state?.audio_enable === 'boolean') {\n setIsRemoteMicMuted(!state.audio_enable);\n }\n if (typeof state?.video_enable === 'boolean') {\n setIsRemoteVideoMuted(!state.video_enable);\n }\n };\n\n // Listen for remote peer requesting to upgrade call (audio → video)\n // Pattern 2: Automatically switch UI layout to video without prompting.\n node.onUpgradeCall = () => {\n setCallType('video');\n // Note: We don't turn on our own camera automatically.\n };\n\n return () => {\n const cleanup = async () => {\n try {\n await node.endCall();\n } catch (e) { } // ignore during unmount\n };\n cleanup();\n };\n }, [client, sessionId, wasmPath, relayUrl, onIncomingCall, onCallError]);\n\n const createCall = useCallback(async (type: 'audio' | 'video', cid: string) => {\n if (!callNode) return;\n setCallType(type);\n setIsIncoming(false);\n \n // Tận dụng Local Cache: Phân giải thông tin đồng bộ ngay trước khi bật modal\n callNode.prefillUserInfo(cid);\n setCallerInfo(callNode.callerInfo);\n setReceiverInfo(callNode.receiverInfo);\n\n setCallStatus(CallStatus.PREPARING);\n await callNode.createCall(type, cid);\n // C1: Lifecycle callback — call started\n onCallStart?.(type, cid);\n }, [callNode, onCallStart]);\n\n const acceptCall = useCallback(async () => {\n if (!callNode) return;\n setIsAccepting(true);\n try {\n await callNode.acceptCall();\n onCallAccepted?.();\n } catch (e) {\n setIsAccepting(false);\n }\n }, [callNode, onCallAccepted]);\n\n const rejectCall = useCallback(async () => {\n if (!callNode) return;\n setIsRejecting(true);\n try {\n await callNode.rejectCall();\n setCallStatus('');\n setIsIncoming(false);\n onCallRejected?.();\n } finally {\n setIsRejecting(false);\n }\n }, [callNode, onCallRejected]);\n\n const endCall = useCallback(async () => {\n if (!callNode) return;\n setIsEnding(true);\n try {\n await callNode.endCall();\n const duration = callDuration;\n setCallStatus('');\n setIsIncoming(false);\n setLocalStream(null);\n setRemoteStream(null);\n onCallEnd?.(duration);\n } finally {\n setIsEnding(false);\n }\n }, [callNode, callDuration, onCallEnd]);\n\n const toggleScreenShare = useCallback(async () => {\n if (!callNode) return;\n if (isScreenSharing) {\n await callNode.stopScreenShare();\n } else {\n await callNode.startScreenShare();\n }\n }, [callNode, isScreenSharing]);\n\n const switchAudioDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchAudioDevice(deviceId);\n if (success) setSelectedAudioDeviceId(deviceId);\n }, [callNode]);\n\n const switchVideoDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchVideoDevice(deviceId);\n if (success) setSelectedVideoDeviceId(deviceId);\n }, [callNode]);\n\n const clearError = useCallback(() => setErrorMessage(null), []);\n const resetCall = useCallback(() => {\n if (callNode) callNode.destroy();\n setCallStatus('');\n setErrorMessage(null);\n setIsIncoming(false);\n setCallDuration(0);\n setCallType('audio');\n }, [callNode]);\n\n const upgradeCall = useCallback(async () => {\n if (!callNode) return;\n await callNode.upgradeCall();\n setCallType('video');\n }, [callNode]);\n\n const toggleMic = useCallback(async () => {\n if (!callNode || !localStream) return;\n const newMutedState = !isMicMuted;\n await callNode.toggleMic(!newMutedState);\n setIsMicMuted(newMutedState);\n }, [callNode, localStream, isMicMuted]);\n\n const toggleVideo = useCallback(async () => {\n if (!callNode) return;\n if (localStream) {\n if (localStream.getVideoTracks().length > 0) {\n const newMutedState = !isVideoMuted;\n await callNode.toggleCamera(!newMutedState);\n setIsVideoMuted(newMutedState);\n } else {\n // One-way video case: we are in a video call but our camera is off (no track).\n // Clicking toggle video should add our camera track via requestUpgradeCall.\n // This avoids sending the UPGRADE_CALL signal to the backend again.\n await callNode.requestUpgradeCall(true);\n setIsVideoMuted(false);\n }\n }\n }, [callNode, localStream, isVideoMuted]);\n\n const value = {\n callNode,\n callStatus,\n localStream,\n remoteStream,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n createCall,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n isRemoteVideoMuted,\n upgradeCall,\n callDuration,\n isAccepting,\n isRejecting,\n isEnding,\n resetCall,\n };\n\n return (\n <ErmisCallContext.Provider value={value}>\n {children}\n </ErmisCallContext.Provider>\n );\n};\n\nErmisCallProvider.displayName = 'ErmisCallProvider';\n","import React from 'react';\nimport { CallStatus, type ErmisCallNode, type UserCallInfo } from '@ermis-network/ermis-chat-sdk';\n\nexport type CallContextValue = {\n callNode: ErmisCallNode | null;\n callStatus: CallStatus | '';\n localStream: MediaStream | null;\n remoteStream: MediaStream | null;\n callType: string;\n callerInfo?: UserCallInfo | undefined;\n receiverInfo?: UserCallInfo | undefined;\n isIncoming: boolean;\n createCall: (type: 'audio' | 'video', cid: string) => Promise<void>;\n acceptCall: () => Promise<void>;\n rejectCall: () => Promise<void>;\n endCall: () => Promise<void>;\n toggleMic: () => void;\n toggleVideo: () => void;\n isMicMuted: boolean;\n isVideoMuted: boolean;\n audioDevices: MediaDeviceInfo[];\n videoDevices: MediaDeviceInfo[];\n selectedAudioDeviceId: string;\n selectedVideoDeviceId: string;\n isScreenSharing: boolean;\n errorMessage: string | null;\n toggleScreenShare: () => Promise<void>;\n switchAudioDevice: (id: string) => Promise<void>;\n switchVideoDevice: (id: string) => Promise<void>;\n clearError: () => void;\n isRemoteMicMuted: boolean;\n isRemoteVideoMuted: boolean;\n upgradeCall: () => Promise<void>;\n callDuration: number;\n isAccepting: boolean;\n isRejecting: boolean;\n isEnding: boolean;\n resetCall: () => void;\n};\n\nexport const ErmisCallContext = React.createContext<CallContextValue | undefined>(undefined);\n","import React, { useEffect, useRef, useState, useCallback } from 'react';\nimport { useCallContext } from '../hooks/useCallContext';\nimport { Modal as DefaultModal } from './Modal';\nimport { Avatar } from './Avatar';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport { CallStatus } from '@ermis-network/ermis-chat-sdk';\nimport type { ErmisCallUIProps } from '../types';\n\n/** Format seconds into MM:SS */\nconst formatDuration = (totalSeconds: number): string => {\n const m = Math.floor(totalSeconds / 60).toString().padStart(2, '0');\n const s = (totalSeconds % 60).toString().padStart(2, '0');\n return `${m}:${s}`;\n};\n\nexport const ErmisCallUI: React.FC<ErmisCallUIProps> = React.memo(({\n className,\n incomingCallTitle = (type: string) => `Incoming ${type} call`,\n outgoingCallTitle = (type: string) => `Outgoing ${type} call`,\n ongoingCallTitle = (type: string) => `Ongoing ${type} Call`,\n isCallingYouLabel = 'is calling you...',\n ringingLabel = 'Ringing...',\n rejectCallLabel = 'Reject',\n acceptCallLabel = 'Accept',\n endCallLabel = 'End Call',\n cancelLabel = 'Cancel',\n toggleMicTitle = 'Toggle Mic',\n toggleVideoTitle = 'Toggle Video',\n shareScreenTitle = 'Share Screen',\n stopScreenShareTitle = 'Stop Sharing',\n connectedLabel = 'Connected',\n audioCallBadgeLabel = 'Audio Call',\n videoCallBadgeLabel = 'Video Call',\n fullscreenTitle = 'Fullscreen',\n exitFullscreenTitle = 'Exit Fullscreen',\n upgradeCallTitle = 'Request Video Upgrade',\n suppressIncomingCalls = false,\n onCallDurationChange,\n AvatarComponent = Avatar,\n MicIcon: PropMicIcon,\n MicOffIcon: PropMicOffIcon,\n VideoIcon: PropVideoIcon,\n VideoOffIcon: PropVideoOffIcon,\n PhoneIcon: PropPhoneIcon,\n ScreenShareIcon: PropScreenShareIcon,\n ScreenShareOffIcon: PropScreenShareOffIcon,\n FullscreenIcon: PropFullscreenIcon,\n ExitFullscreenIcon: PropExitFullscreenIcon,\n UpgradeCallIcon: PropUpgradeCallIcon,\n incomingCallAudioPath = '/call_incoming.mp3',\n outgoingCallAudioPath = '/call_outgoing.mp3',\n RingingComponent: CustomRingingComponent,\n ConnectedAudioComponent: CustomConnectedAudioComponent,\n ConnectedVideoComponent: CustomConnectedVideoComponent,\n ErrorComponent: CustomErrorComponent,\n ControlsBarComponent: CustomControlsBarComponent,\n}) => {\n const {\n callStatus,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n localStream,\n remoteStream,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n upgradeCall,\n callDuration,\n isAccepting,\n isRejecting,\n isEnding,\n } = useCallContext();\n\n const { ModalComponent } = useChatComponents();\n const Modal = ModalComponent || DefaultModal;\n\n const localVideoRef = useRef<HTMLVideoElement>(null);\n const remoteVideoRef = useRef<HTMLVideoElement>(null);\n const remoteAudioRef = useRef<HTMLAudioElement>(null);\n const ringingAudioRef = useRef<HTMLAudioElement>(null);\n const callContainerRef = useRef<HTMLDivElement>(null);\n\n // Fullscreen state\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n const toggleFullscreen = useCallback(() => {\n if (!callContainerRef.current) return;\n if (!document.fullscreenElement) {\n callContainerRef.current.requestFullscreen?.().catch(() => {});\n } else {\n document.exitFullscreen?.().catch(() => {});\n }\n }, []);\n\n useEffect(() => {\n const handleChange = () => setIsFullscreen(!!document.fullscreenElement);\n document.addEventListener('fullscreenchange', handleChange);\n return () => document.removeEventListener('fullscreenchange', handleChange);\n }, []);\n\n // C5: Notify consumer of duration changes\n useEffect(() => {\n if (callDuration > 0) {\n onCallDurationChange?.(callDuration);\n }\n }, [callDuration, onCallDurationChange]);\n\n useEffect(() => {\n if (localVideoRef.current && localStream) {\n localVideoRef.current.srcObject = localStream;\n }\n }, [localStream, callType, callStatus]);\n\n useEffect(() => {\n if (remoteStream) {\n if (callType === 'video' && remoteVideoRef.current) {\n remoteVideoRef.current.srcObject = remoteStream;\n }\n if (remoteAudioRef.current) {\n remoteAudioRef.current.srcObject = remoteStream;\n }\n }\n }, [remoteStream, callType, callStatus]);\n\n useEffect(() => {\n if (callStatus === CallStatus.RINGING && ringingAudioRef.current) {\n const playPromise = ringingAudioRef.current.play();\n if (playPromise !== undefined) {\n playPromise.catch((e) => console.log('ErmisChat: Audio play blocked by browser:', e));\n }\n } else if (ringingAudioRef.current) {\n ringingAudioRef.current.pause();\n ringingAudioRef.current.currentTime = 0;\n }\n }, [callStatus]);\n\n if (!callStatus && !errorMessage) return null;\n\n // C3: Suppress incoming call UI (DND mode)\n if (suppressIncomingCalls && isIncoming && callStatus === CallStatus.RINGING) return null;\n\n const isOpen = callStatus === CallStatus.RINGING || callStatus === CallStatus.CONNECTED || !!errorMessage;\n if (!isOpen) return null;\n\n const title = errorMessage ? 'Call Error' : (\n callStatus === CallStatus.RINGING\n ? (isIncoming ? incomingCallTitle(callType) : outgoingCallTitle(callType))\n : ongoingCallTitle(callType)\n );\n\n const peerInfo = isIncoming ? callerInfo : receiverInfo;\n const modalMaxWidth = callType === 'video' && callStatus === CallStatus.CONNECTED ? '720px' : '480px';\n\n // Default icons\n const FinalPhoneIcon = PropPhoneIcon || (() => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n ));\n\n const FinalVideoIcon = PropVideoIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n ));\n\n const FinalVideoOffIcon = PropVideoOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 16v1a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2m5.66 0H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10M1 1l22 22\"></path>\n </svg>\n ));\n\n const FinalMicIcon = PropMicIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"></path>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalMicOffIcon = PropMicOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"></path>\n <path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalScreenShareIcon = PropScreenShareIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <path d=\"M16 11l-4 4-4-4\"></path>\n <path d=\"M12 15V7\"></path>\n </svg>\n ));\n\n const FinalScreenShareOffIcon = PropScreenShareOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"10\"></line>\n </svg>\n ));\n\n const FinalFullscreenIcon = PropFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3\"></path>\n <path d=\"M21 8V5a2 2 0 0 0-2-2h-3\"></path>\n <path d=\"M3 16v3a2 2 0 0 0 2 2h3\"></path>\n <path d=\"M16 21h3a2 2 0 0 0 2-2v-3\"></path>\n </svg>\n ));\n\n const FinalExitFullscreenIcon = PropExitFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4 14h6v6\"></path>\n <path d=\"M20 10h-6V4\"></path>\n <path d=\"M14 10l7-7\"></path>\n <path d=\"M3 21l7-7\"></path>\n </svg>\n ));\n\n // C4: Upgrade call icon (defaults to FinalVideoIcon)\n const FinalUpgradeCallIcon = PropUpgradeCallIcon || FinalVideoIcon;\n\n /* ================================================================\n Shared Controls Bar — used by both audio and video active states\n ================================================================ */\n const renderControls = () => {\n // C6: Allow consumer to replace controls bar entirely\n if (CustomControlsBarComponent) {\n return (\n <CustomControlsBarComponent\n callType={callType}\n toggleMic={toggleMic}\n toggleVideo={toggleVideo}\n toggleScreenShare={toggleScreenShare}\n toggleFullscreen={toggleFullscreen}\n upgradeCall={upgradeCall}\n endCall={endCall}\n isMicMuted={isMicMuted}\n isVideoMuted={isVideoMuted}\n isScreenSharing={isScreenSharing}\n isFullscreen={isFullscreen}\n isEnding={isEnding}\n audioDevices={audioDevices}\n videoDevices={videoDevices}\n selectedAudioDeviceId={selectedAudioDeviceId}\n selectedVideoDeviceId={selectedVideoDeviceId}\n switchAudioDevice={switchAudioDevice}\n switchVideoDevice={switchVideoDevice}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__controls\">\n {/* Mic */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleMic}\n className={`ermis-call-ui__control-btn ${isMicMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleMicTitle}\n >\n {isMicMuted ? <FinalMicOffIcon /> : <FinalMicIcon />}\n </button>\n {audioDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedAudioDeviceId}\n onChange={(e) => switchAudioDevice(e.target.value)}\n >\n {audioDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Microphone'}</option>\n ))}\n </select>\n )}\n </div>\n\n {/* Video controls */}\n {callType === 'video' ? (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleVideo}\n className={`ermis-call-ui__control-btn ${isVideoMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleVideoTitle}\n >\n {isVideoMuted ? <FinalVideoOffIcon /> : <FinalVideoIcon />}\n </button>\n {videoDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedVideoDeviceId}\n onChange={(e) => switchVideoDevice(e.target.value)}\n >\n {videoDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Camera'}</option>\n ))}\n </select>\n )}\n </div>\n ) : (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={upgradeCall}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={upgradeCallTitle}\n >\n <FinalUpgradeCallIcon />\n </button>\n </div>\n )}\n\n {/* Screen Share */}\n {callType === 'video' && typeof navigator.mediaDevices?.getDisplayMedia === 'function' && (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleScreenShare}\n className={`ermis-call-ui__control-btn ${isScreenSharing ? 'ermis-call-ui__control-btn--active' : ''}`}\n data-tooltip={isScreenSharing ? stopScreenShareTitle : shareScreenTitle}\n >\n {isScreenSharing ? <FinalScreenShareIcon /> : <FinalScreenShareOffIcon />}\n </button>\n </div>\n )}\n\n {/* Fullscreen */}\n {callType === 'video' && (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleFullscreen}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={isFullscreen ? exitFullscreenTitle : fullscreenTitle}\n >\n {isFullscreen ? <FinalExitFullscreenIcon /> : <FinalFullscreenIcon />}\n </button>\n </div>\n )}\n\n {/* Separator before end call */}\n <div className=\"ermis-call-ui__controls-separator\" />\n\n {/* End Call */}\n <button\n onClick={endCall}\n disabled={isEnding}\n className=\"ermis-call-ui__control-btn ermis-call-ui__control-btn--danger\"\n data-tooltip={endCallLabel}\n >\n {isEnding ? <div className=\"ermis-call-ui__spinner\" /> : <FinalPhoneIcon />}\n </button>\n </div>\n );\n };\n\n /* ================================================================\n Render ringing state\n ================================================================ */\n const renderRinging = () => {\n // C6: Allow consumer to replace ringing view entirely\n if (CustomRingingComponent) {\n return (\n <CustomRingingComponent\n peerInfo={peerInfo}\n callType={callType}\n isIncoming={isIncoming}\n acceptCall={acceptCall}\n rejectCall={rejectCall}\n endCall={endCall}\n AvatarComponent={AvatarComponent}\n isCallingYouLabel={isCallingYouLabel}\n ringingLabel={ringingLabel}\n rejectCallLabel={rejectCallLabel}\n acceptCallLabel={acceptCallLabel}\n endCallLabel={endCallLabel}\n audioCallBadgeLabel={audioCallBadgeLabel}\n videoCallBadgeLabel={videoCallBadgeLabel}\n isAccepting={isAccepting}\n isRejecting={isRejecting}\n isEnding={isEnding}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__ringing\">\n {/* Avatar with pulse rings */}\n <div className=\"ermis-call-ui__ringing-avatar\">\n <div className=\"ermis-call-ui__ringing-avatar-inner\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={88}\n />\n </div>\n </div>\n\n <h3 className=\"ermis-call-ui__ringing-name\">\n {peerInfo?.name}\n </h3>\n <p className=\"ermis-call-ui__ringing-status\">\n {isIncoming ? isCallingYouLabel : ringingLabel}\n </p>\n\n {/* Call type badge */}\n <div className=\"ermis-call-ui__type-badge\">\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n {callType === 'video' ? videoCallBadgeLabel : audioCallBadgeLabel}\n </div>\n\n {/* Action buttons */}\n <div className=\"ermis-call-ui__ringing-actions\">\n {isIncoming ? (\n <>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={rejectCall}\n disabled={isRejecting}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n {isRejecting ? <div className=\"ermis-call-ui__spinner\" /> : <FinalPhoneIcon />}\n </button>\n <span className=\"ermis-call-ui__action-label\">{rejectCallLabel}</span>\n </div>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={acceptCall}\n disabled={isAccepting}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--accept\"\n >\n {isAccepting ? (\n <div className=\"ermis-call-ui__spinner\" />\n ) : (\n callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />\n )}\n </button>\n <span className=\"ermis-call-ui__action-label\">{acceptCallLabel}</span>\n </div>\n </>\n ) : (\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={endCall}\n disabled={isEnding}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n {isEnding ? <div className=\"ermis-call-ui__spinner\" /> : <FinalPhoneIcon />}\n </button>\n <span className=\"ermis-call-ui__action-label\">{endCallLabel}</span>\n </div>\n )}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render connected state\n ================================================================ */\n const renderConnected = () => {\n if (callType === 'video') {\n // C6: Allow consumer to replace connected video view\n if (CustomConnectedVideoComponent) {\n return (\n <CustomConnectedVideoComponent\n localVideoRef={localVideoRef}\n remoteVideoRef={remoteVideoRef}\n isRemoteMicMuted={isRemoteMicMuted}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__video-container\">\n <video\n ref={remoteVideoRef}\n autoPlay\n playsInline\n className=\"ermis-call-ui__video-remote\"\n />\n <div className=\"ermis-call-ui__video-local\">\n <video\n ref={localVideoRef}\n autoPlay\n playsInline\n muted\n className=\"ermis-call-ui__video-local-stream\"\n />\n </div>\n {/* Call status bar: mic-muted indicator + duration timer */}\n <div className=\"ermis-call-ui__video-timer\">\n {isRemoteMicMuted && (\n <span className=\"ermis-call-ui__video-timer-mic\"><FinalMicOffIcon /></span>\n )}\n <span className=\"ermis-call-ui__active-status-dot\" />\n <span>{formatDuration(callDuration)}</span>\n </div>\n {/* Glassmorphism controls overlay */}\n <div className=\"ermis-call-ui__video-controls-overlay\">\n {renderControls()}\n </div>\n </div>\n </div>\n );\n }\n\n // Audio call\n // C6: Allow consumer to replace connected audio view\n if (CustomConnectedAudioComponent) {\n return (\n <CustomConnectedAudioComponent\n peerInfo={peerInfo}\n callDuration={callDuration}\n isRemoteMicMuted={isRemoteMicMuted}\n AvatarComponent={AvatarComponent}\n connectedLabel={connectedLabel}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__audio-container\">\n <div className=\"ermis-call-ui__audio-avatar-wrapper\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={100}\n />\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge ermis-call-ui__remote-muted-badge--audio\">\n <FinalMicOffIcon />\n </div>\n )}\n </div>\n <h3 className=\"ermis-call-ui__active-name\">\n {peerInfo?.name}\n </h3>\n\n {/* Status + Timer */}\n <div className=\"ermis-call-ui__active-status\">\n <span className=\"ermis-call-ui__active-status-dot\" />\n <span>{connectedLabel}</span>\n <span className=\"ermis-call-ui__timer\">\n {formatDuration(callDuration)}\n </span>\n </div>\n\n {/* Audio wave visualizer */}\n <div className=\"ermis-call-ui__audio-waves\">\n {Array.from({ length: 9 }).map((_, i) => (\n <span key={i} className=\"ermis-call-ui__audio-wave-bar\" />\n ))}\n </div>\n\n <audio ref={remoteAudioRef} autoPlay className=\"ermis-call-ui__audio--hidden\" />\n\n {/* Controls bar */}\n {renderControls()}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render error state\n ================================================================ */\n const renderError = () => {\n if (!errorMessage) return null;\n\n // C6: Allow consumer to replace error view\n if (CustomErrorComponent) {\n return (\n <CustomErrorComponent\n errorMessage={errorMessage}\n clearError={clearError}\n cancelLabel={cancelLabel}\n PhoneIcon={FinalPhoneIcon}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__error\">\n <div className=\"ermis-call-ui__error-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--ermis-color-danger)\" strokeWidth=\"2\" width=\"56\" height=\"56\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n </div>\n <p className=\"ermis-call-ui__error-text\">{errorMessage}</p>\n <button\n className=\"ermis-call-ui__error-dismiss\"\n onClick={clearError}\n >\n <FinalPhoneIcon /> {cancelLabel}\n </button>\n </div>\n );\n };\n\n return (\n <Modal isOpen={isOpen} onClose={endCall} title={title} hideCloseButton closeOnOutsideClick={false} maxWidth={modalMaxWidth}>\n <div className={`ermis-call-ui ${isFullscreen ? 'ermis-call-ui--fullscreen' : ''}${className ? ` ${className}` : ''}`} ref={callContainerRef}>\n {/* Ringing audio */}\n {(incomingCallAudioPath || outgoingCallAudioPath) && (\n <audio\n ref={ringingAudioRef}\n src={isIncoming ? incomingCallAudioPath : outgoingCallAudioPath}\n loop\n className=\"ermis-call-ui__audio--hidden\"\n />\n )}\n\n {/* ============ ERROR STATE ============ */}\n {errorMessage && renderError()}\n\n {/* ============ RINGING STATE ============ */}\n {!errorMessage && callStatus === CallStatus.RINGING && renderRinging()}\n\n {/* ============ CONNECTED STATE ============ */}\n {!errorMessage && callStatus === CallStatus.CONNECTED && renderConnected()}\n </div>\n </Modal>\n );\n});\n\nErmisCallUI.displayName = 'ErmisCallUI';\n","import { useContext } from 'react';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\n\nexport const useCallContext = () => {\n const context = useContext(ErmisCallContext);\n if (context === undefined) {\n throw new Error('useCallContext must be used within an ErmisCallProvider');\n }\n return context;\n};\n","import React, { useEffect } from 'react';\nimport type { ModalProps } from '../types';\n\nexport const Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n children,\n footer,\n maxWidth = '480px',\n hideCloseButton = false,\n closeOnOutsideClick = true,\n}) => {\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen) onClose();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"ermis-modal-overlay\" onClick={closeOnOutsideClick ? onClose : undefined}>\n <div \n className=\"ermis-modal-content\" \n style={{ maxWidth }} \n onClick={e => e.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <div className=\"ermis-modal-header\">\n {title ? (\n typeof title === 'string' ? <h3>{title}</h3> : title\n ) : <div />}\n {!hideCloseButton && (\n <button className=\"ermis-modal-close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n )}\n </div>\n )}\n\n <div className=\"ermis-modal-body\">\n {children}\n </div>\n\n {footer && (\n <div className=\"ermis-modal-footer\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n","import React, { useMemo, useState } from 'react';\nimport { MediaLightbox } from './MediaLightbox';\nimport { getAvatarGradient } from '../utils/avatarColors';\nimport type { AvatarProps } from '../types';\n\nexport type { AvatarProps } from '../types';\n\n/**\n * Extracts 1–2 initials from a name.\n */\nfunction getInitials(name?: string): string {\n if (!name) return '?';\n if (name.startsWith('0x')) return '0x';\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n }\n return parts[0][0].toUpperCase();\n}\n\n/**\n * Avatar component with image or initial fallback.\n */\nexport const Avatar: React.FC<AvatarProps> = React.memo(({\n image,\n name,\n size = 36,\n className,\n disableLightbox,\n}) => {\n const [isLoaded, setIsLoaded] = useState(false);\n const [hasError, setHasError] = useState(false);\n const [isLightboxOpen, setIsLightboxOpen] = useState(false);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Reset state if image URL changes\n React.useEffect(() => {\n if (image) {\n setHasError(false);\n if (imgRef.current?.complete) {\n setIsLoaded(true);\n } else {\n setIsLoaded(false);\n }\n }\n }, [image]);\n\n const initials = useMemo(() => getInitials(name), [name]);\n\n const wrapperStyle = useMemo<React.CSSProperties>(() => ({\n width: size,\n height: size,\n minWidth: size,\n position: 'relative',\n borderRadius: '100%', /* Or var(--ermis-radius-full) */\n overflow: 'hidden',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: image && !hasError && !disableLightbox ? 'pointer' : undefined,\n }), [size, image, hasError, disableLightbox]);\n\n const contentStyle = useMemo<React.CSSProperties>(() => ({\n width: '100%',\n height: '100%',\n fontSize: size * 0.4,\n lineHeight: 1,\n }), [size]);\n\n const handleAvatarClick = React.useCallback((e: React.MouseEvent) => {\n if (image && !hasError && !disableLightbox) {\n e.stopPropagation();\n e.preventDefault();\n setIsLightboxOpen(true);\n }\n }, [image, hasError, disableLightbox]);\n\n return (\n <>\n <div \n className={`ermis-avatar-wrapper${className ? ` ${className}` : ''}`} \n style={wrapperStyle}\n onClick={handleAvatarClick}\n >\n {/* 1. Underlying Fallback (Placeholder) */}\n <div\n className=\"ermis-avatar ermis-avatar--fallback\"\n style={{ ...contentStyle, background: getAvatarGradient(name) }}\n title={name}\n >\n {initials}\n </div>\n\n {/* 2. Actual Image (Lazy, Fades in natively using CSS opacity) */}\n {image && !hasError && (\n <img\n ref={imgRef}\n className=\"ermis-avatar__img\"\n src={image}\n alt={name || 'Avatar'}\n loading=\"lazy\"\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasError(true)}\n style={{\n ...contentStyle,\n position: 'absolute',\n top: 0,\n left: 0,\n opacity: isLoaded ? 1 : 0,\n transition: 'opacity 0.3s ease-in-out',\n objectFit: 'cover',\n }}\n />\n )}\n </div>\n\n {isLightboxOpen && image && !hasError && (\n <MediaLightbox\n items={[{ type: 'image', src: image, alt: name || 'Avatar' }]}\n isOpen={isLightboxOpen}\n onClose={() => setIsLightboxOpen(false)}\n />\n )}\n </>\n );\n});\n\nAvatar.displayName = 'Avatar';\n","import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport ReactDOM from 'react-dom';\nimport { preloadImage } from '../utils';\nimport { useDownloadHandler } from '../hooks/useDownloadHandler';\nimport type { MediaLightboxItem, MediaLightboxProps } from '../types';\n\n/** Max retry attempts for video loading (CDN may not be ready for large uploads) */\nconst VIDEO_MAX_RETRIES = 3;\n/** Base delay in ms for exponential backoff: 1s, 2s, 4s */\nconst VIDEO_RETRY_BASE_DELAY = 1000;\n\n/**\n * MediaLightbox – full-screen overlay for viewing images & videos.\n * Supports prev/next navigation, keyboard controls, and image zoom.\n * Renders via React portal into document.body.\n */\nexport const MediaLightbox: React.FC<MediaLightboxProps> = React.memo(\n ({ items, initialIndex = 0, isOpen, onClose }) => {\n const [currentIndex, setCurrentIndex] = useState(initialIndex);\n const [zoom, setZoom] = useState(1);\n const [pan, setPan] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const dragStart = useRef({ x: 0, y: 0 });\n const panStart = useRef({ x: 0, y: 0 });\n const videoRef = useRef<HTMLVideoElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const currentDisposeRef = useRef<MediaLightboxItem['onDispose']>();\n\n // Video retry state — handles CDN not-ready for large recently-uploaded files\n const [videoRetryCount, setVideoRetryCount] = useState(0);\n const [videoLoading, setVideoLoading] = useState(false);\n const videoRetryTimerRef = useRef<ReturnType<typeof setTimeout>>();\n const pendingVideoSeekTimeRef = useRef<number | undefined>();\n\n // Reset state when opening or when items change\n useEffect(() => {\n if (isOpen) {\n setCurrentIndex(initialIndex);\n setZoom(1);\n setPan({ x: 0, y: 0 });\n setVideoRetryCount(0);\n setVideoLoading(false);\n pendingVideoSeekTimeRef.current = undefined;\n }\n return () => {\n if (videoRetryTimerRef.current) clearTimeout(videoRetryTimerRef.current);\n };\n }, [isOpen, initialIndex]);\n\n // Preload adjacent images\n useEffect(() => {\n if (!isOpen) return;\n const preloadIdx = [currentIndex - 1, currentIndex + 1];\n preloadIdx.forEach((idx) => {\n if (idx >= 0 && idx < items.length && items[idx].type === 'image' && items[idx].src) {\n preloadImage(items[idx].src);\n }\n });\n }, [isOpen, currentIndex, items]);\n\n useEffect(() => {\n currentDisposeRef.current = items[currentIndex]?.onDispose;\n });\n\n // Pause video and dispose virtual E2EE stream sessions when navigating away or closing.\n // Do not depend on items: callers often rebuild the items array after progress/state changes.\n useEffect(() => {\n return () => {\n if (videoRef.current) {\n videoRef.current.pause();\n }\n const dispose = currentDisposeRef.current;\n currentDisposeRef.current = undefined;\n void dispose?.();\n };\n }, [currentIndex]);\n\n // Lock body scroll when open\n useEffect(() => {\n if (isOpen) {\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = prev;\n };\n }\n }, [isOpen]);\n\n const goTo = useCallback((idx: number) => {\n if (videoRef.current) videoRef.current.pause();\n if (videoRetryTimerRef.current) clearTimeout(videoRetryTimerRef.current);\n setCurrentIndex(idx);\n setZoom(1);\n setPan({ x: 0, y: 0 });\n setVideoRetryCount(0);\n setVideoLoading(false);\n pendingVideoSeekTimeRef.current = undefined;\n }, []);\n\n const goPrev = useCallback(() => {\n if (currentIndex > 0) goTo(currentIndex - 1);\n }, [currentIndex, goTo]);\n\n const goNext = useCallback(() => {\n if (currentIndex < items.length - 1) goTo(currentIndex + 1);\n }, [currentIndex, items.length, goTo]);\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return;\n const handleKey = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'Escape':\n onClose();\n break;\n case 'ArrowLeft':\n goPrev();\n break;\n case 'ArrowRight':\n goNext();\n break;\n }\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose, goPrev, goNext]);\n\n // Double-click zoom toggle (image only)\n const handleDoubleClick = useCallback(() => {\n const current = items[currentIndex];\n if (current?.type !== 'image') return;\n\n if (zoom === 1) {\n setZoom(2);\n } else {\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }\n }, [currentIndex, items, zoom]);\n\n // Wheel zoom (image only)\n const handleWheel = useCallback(\n (e: React.WheelEvent) => {\n const current = items[currentIndex];\n if (current?.type !== 'image') return;\n e.preventDefault();\n\n setZoom((prev) => {\n const next = prev - e.deltaY * 0.002;\n const clamped = Math.max(1, Math.min(3, next));\n if (clamped === 1) setPan({ x: 0, y: 0 });\n return clamped;\n });\n },\n [currentIndex, items],\n );\n\n // Mouse drag for panning (image zoomed)\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (zoom <= 1) return;\n e.preventDefault();\n setIsDragging(true);\n dragStart.current = { x: e.clientX, y: e.clientY };\n panStart.current = { ...pan };\n },\n [zoom, pan],\n );\n\n const handleMouseMove = useCallback(\n (e: React.MouseEvent) => {\n if (!isDragging) return;\n const dx = e.clientX - dragStart.current.x;\n const dy = e.clientY - dragStart.current.y;\n setPan({ x: panStart.current.x + dx, y: panStart.current.y + dy });\n },\n [isDragging],\n );\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n // Click on backdrop closes\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target === containerRef.current) {\n onClose();\n }\n },\n [onClose],\n );\n\n const { downloadFile } = useDownloadHandler();\n\n const currentItem = items[currentIndex];\n const hasMultiple = items.length > 1;\n\n const handleDownload = useCallback(async () => {\n if (!currentItem) return;\n if (currentItem.download) {\n await currentItem.download();\n return;\n }\n if (!currentItem.src) return;\n await downloadFile(currentItem.src, currentItem.alt || 'media');\n }, [currentItem, downloadFile]);\n\n const restorePendingVideoSeekTime = useCallback(() => {\n setVideoLoading(false);\n const seekTime = pendingVideoSeekTimeRef.current;\n const video = videoRef.current;\n if (seekTime === undefined || !video || !Number.isFinite(seekTime) || seekTime <= 0) return;\n try {\n if (!Number.isFinite(video.duration) || seekTime < video.duration) {\n video.currentTime = seekTime;\n }\n pendingVideoSeekTimeRef.current = undefined;\n } catch {\n pendingVideoSeekTimeRef.current = undefined;\n }\n }, []);\n\n // Video error handler — retries loading with exponential backoff\n // Handles CDN not-ready scenario for large recently-uploaded files\n const handleVideoError = useCallback(() => {\n if (currentItem?.onPlaybackError) {\n if (videoRetryTimerRef.current) clearTimeout(videoRetryTimerRef.current);\n const currentTime = videoRef.current?.currentTime;\n pendingVideoSeekTimeRef.current =\n currentTime !== undefined && Number.isFinite(currentTime) && currentTime > 0 ? currentTime : undefined;\n setVideoLoading(true);\n void Promise.resolve(currentItem.onPlaybackError({ currentTime: pendingVideoSeekTimeRef.current })).finally(\n () => {\n setVideoLoading(false);\n setVideoRetryCount(0);\n },\n );\n return;\n }\n setVideoRetryCount((prev) => {\n if (prev >= VIDEO_MAX_RETRIES) return prev;\n const nextAttempt = prev + 1;\n const delay = VIDEO_RETRY_BASE_DELAY * Math.pow(2, prev); // 1s, 2s, 4s\n setVideoLoading(true);\n videoRetryTimerRef.current = setTimeout(() => {\n // Force the video element to re-attempt loading by resetting src\n if (videoRef.current) {\n const src = videoRef.current.src;\n videoRef.current.src = '';\n videoRef.current.src = src;\n videoRef.current.load();\n }\n setVideoLoading(false);\n }, delay);\n return nextAttempt;\n });\n }, [currentItem]);\n\n const content = useMemo(() => {\n if (!currentItem) return null;\n\n const loadingOverlay = currentItem.loading || !currentItem.src;\n if (currentItem.type === 'video') {\n return (\n <div className=\"ermis-lightbox__video-wrapper\">\n {currentItem.src ? (\n <video\n ref={videoRef}\n className=\"ermis-lightbox__video\"\n src={currentItem.src}\n poster={currentItem.posterSrc}\n controls\n autoPlay\n preload=\"metadata\"\n onClick={(e) => e.stopPropagation()}\n onLoadedMetadata={restorePendingVideoSeekTime}\n onCanPlay={restorePendingVideoSeekTime}\n onPlaying={() => setVideoLoading(false)}\n onError={handleVideoError}\n />\n ) : currentItem.posterSrc ? (\n <img\n className=\"ermis-lightbox__image ermis-lightbox__image--poster\"\n src={currentItem.posterSrc}\n alt={currentItem.alt || ''}\n />\n ) : (\n <div className=\"ermis-lightbox__media-placeholder\" />\n )}\n {(videoLoading || loadingOverlay) && (\n <div className=\"ermis-lightbox__video-retry\">\n <div className=\"ermis-lightbox__video-spinner\" />\n {currentItem.progressLabel && (\n <span className=\"ermis-lightbox__progress-label\">{currentItem.progressLabel}</span>\n )}\n </div>\n )}\n </div>\n );\n }\n\n const imgStyle: React.CSSProperties = {\n transform: `scale(${zoom}) translate(${pan.x / zoom}px, ${pan.y / zoom}px)`,\n cursor: zoom > 1 ? (isDragging ? 'grabbing' : 'grab') : 'default',\n };\n\n if (!currentItem.src) {\n return (\n <div className=\"ermis-lightbox__video-wrapper\">\n {currentItem.posterSrc ? (\n <img\n className=\"ermis-lightbox__image ermis-lightbox__image--poster\"\n src={currentItem.posterSrc}\n alt={currentItem.alt || ''}\n />\n ) : (\n <div className=\"ermis-lightbox__media-placeholder\" />\n )}\n <div className=\"ermis-lightbox__video-retry\">\n <div className=\"ermis-lightbox__video-spinner\" />\n {currentItem.progressLabel && (\n <span className=\"ermis-lightbox__progress-label\">{currentItem.progressLabel}</span>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <img\n className={`ermis-lightbox__image${zoom > 1 ? ' ermis-lightbox__image--zoomed' : ''}`}\n src={currentItem.src}\n alt={currentItem.alt || ''}\n style={imgStyle}\n draggable={false}\n onDoubleClick={handleDoubleClick}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n onClick={(e) => e.stopPropagation()}\n />\n );\n }, [\n currentItem,\n zoom,\n pan,\n isDragging,\n videoLoading,\n handleDoubleClick,\n handleVideoError,\n restorePendingVideoSeekTime,\n handleMouseDown,\n handleMouseMove,\n handleMouseUp,\n ]);\n\n if (!isOpen || !currentItem) return null;\n\n return ReactDOM.createPortal(\n <div className=\"ermis-lightbox\" onWheel={handleWheel}>\n <div className=\"ermis-lightbox__backdrop\" />\n\n {/* Header: counter + actions */}\n <div className=\"ermis-lightbox__header\">\n {hasMultiple && (\n <span className=\"ermis-lightbox__counter\">\n {currentIndex + 1} / {items.length}\n </span>\n )}\n <div className=\"ermis-lightbox__actions\">\n <button\n className=\"ermis-lightbox__action-btn\"\n onClick={handleDownload}\n aria-label=\"Download\"\n title=\"Download\"\n disabled={Boolean(currentItem.loading) || (!currentItem.src && !currentItem.download)}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n <button className=\"ermis-lightbox__action-btn\" onClick={onClose} aria-label=\"Close\" title=\"Close\">\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Main content area */}\n <div ref={containerRef} className=\"ermis-lightbox__content\" onClick={handleBackdropClick}>\n {/* Prev button */}\n {hasMultiple && currentIndex > 0 && (\n <button\n className=\"ermis-lightbox__nav ermis-lightbox__nav--prev\"\n onClick={(e) => {\n e.stopPropagation();\n goPrev();\n }}\n aria-label=\"Previous\"\n >\n <svg\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n )}\n\n {/* Media */}\n {content}\n\n {/* Next button */}\n {hasMultiple && currentIndex < items.length - 1 && (\n <button\n className=\"ermis-lightbox__nav ermis-lightbox__nav--next\"\n onClick={(e) => {\n e.stopPropagation();\n goNext();\n }}\n aria-label=\"Next\"\n >\n <svg\n width=\"28\"\n height=\"28\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Filename */}\n {currentItem.alt && <div className=\"ermis-lightbox__filename\">{currentItem.alt}</div>}\n </div>,\n document.body,\n );\n },\n);\nMediaLightbox.displayName = 'MediaLightbox';\n","import React from 'react';\nimport type { MentionMember } from './types';\nimport type { Attachment, FormatMessageResponse, Channel } from '@ermis-network/ermis-chat-sdk';\nimport {\n parseSystemMessage,\n parseSignalMessage,\n SystemMessageTranslations,\n SignalMessageTranslations,\n} from '@ermis-network/ermis-chat-sdk';\nimport { isDeletedDisplayMessage } from './messageTypeUtils';\n\n/**\n * Remove Vietnamese diacritics (accents) from a string.\n */\nexport function removeAccents(str: string): string {\n if (!str) return '';\n return str\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/đ/g, 'd')\n .replace(/Đ/g, 'D');\n}\n\n/**\n * Format a Date or date-string to a short time string (HH:MM, 24-hour).\n * Matches Telegram's compact time display.\n */\nexport function formatTime(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const hours = String(d.getHours()).padStart(2, '0');\n const minutes = String(d.getMinutes()).padStart(2, '0');\n return `${hours}:${minutes}`;\n}\n\n/**\n * Format a date as \"HH:MM, Today\", \"HH:MM, Yesterday\", or \"HH:MM, MM/DD/YYYY\".\n */\nexport function formatReadTimestamp(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n const time = d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\n if (diffDays === 0) return `${time}, Today`;\n if (diffDays === 1) return `${time}, Yesterday`;\n const mm = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n const yyyy = d.getFullYear();\n return `${time}, ${mm}/${dd}/${yyyy}`;\n}\n\n/**\n * Return a YYYY-M-D key for date comparison (used by date separators).\n */\nexport function getDateKey(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;\n}\n\n/**\n * Format a date into a human-friendly label (Today / Yesterday / full date).\n * When `locale` is provided, \"Today\" / \"Yesterday\" are localised via\n * `Intl.RelativeTimeFormat` and the full date uses that locale for formatting.\n */\nexport function formatDateLabel(date: Date | string | undefined, locale?: string): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n\n if (diffDays === 0) {\n if (locale && typeof Intl !== 'undefined' && Intl.RelativeTimeFormat) {\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });\n // Format -0 days → \"today\" / \"hôm nay\" etc.\n const parts = rtf.formatToParts(0, 'day');\n const label = parts.map((p) => p.value).join('');\n return label.charAt(0).toUpperCase() + label.slice(1);\n }\n return 'Today';\n }\n if (diffDays === 1) {\n if (locale && typeof Intl !== 'undefined' && Intl.RelativeTimeFormat) {\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });\n const parts = rtf.formatToParts(-1, 'day');\n const label = parts.map((p) => p.value).join('');\n return label.charAt(0).toUpperCase() + label.slice(1);\n }\n return 'Yesterday';\n }\n return d.toLocaleDateString(locale || undefined, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n}\n\n/**\n * Get the user id from a message, checking multiple possible sources.\n */\nexport function getMessageUserId(message: FormatMessageResponse): string {\n return message.user?.id || message.user_id || '';\n}\n\n/**\n * Replace @user_id with @UserName for plain text previews.\n * Returns the formatted string.\n */\nexport function replaceMentionsForPreview(\n text: string,\n message: FormatMessageResponse | { mentioned_users?: any[]; mentioned_all?: boolean },\n userMap: Record<string, string>,\n renderWrapper?: (userId: string, name: string) => string,\n): string {\n const mentionedUsers: any[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, nothing to replace\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return text;\n }\n\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userItem of mentionedUsers) {\n if (!userItem) continue;\n const userId = typeof userItem === 'string' ? userItem : userItem.id;\n if (!userId) continue;\n const itemObjName = typeof userItem === 'object' ? userItem.name : undefined;\n const name = userMap[userId] ?? itemObjName ?? userId;\n replacements.push({\n pattern: `@${userId}`,\n label: renderWrapper ? renderWrapper(userId, name) : `@${name}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({\n pattern: '@all',\n label: renderWrapper ? renderWrapper('__all__', 'all') : '@all',\n });\n }\n\n if (replacements.length === 0) return text;\n\n // Escape special regex characters in the patterns\n const escaped = replacements.map((r) => r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n // Map pattern back to label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return text.replace(regex, (match) => patternToLabel.get(match) || match);\n}\n\n/**\n * Common helper to build a dictionary of User ID -> Display Name\n * from the channel state, used for rendering Mentions and System logs.\n */\nexport function buildUserMap(channelState: any, extraUsers?: Record<string, any>): Record<string, string> {\n const map: Record<string, string> = {};\n const setDisplayName = (id: string, name?: string) => {\n if (!id || !name) return;\n const current = map[id];\n if (current && current !== id) return;\n map[id] = name;\n };\n\n // 1. Fallback: Global user cache from client state\n if (extraUsers && typeof extraUsers === 'object') {\n for (const [id, user] of Object.entries<any>(extraUsers)) {\n setDisplayName(id, user?.name);\n }\n }\n\n // 2. Current members\n const members = channelState?.members;\n if (members && typeof members === 'object') {\n for (const [id, member] of Object.entries<any>(members)) {\n const name = member?.user?.name || member?.user_id || id;\n setDisplayName(id, name);\n }\n }\n\n // 3. Fallback: scan latest messages\n const messages = channelState?.latestMessages;\n if (Array.isArray(messages)) {\n messages.forEach((msg: any) => {\n const u = msg.user;\n setDisplayName(u?.id, u?.name);\n });\n }\n\n // 4. Fallback: check watchers\n const watchers = channelState?.watchers;\n if (watchers && typeof watchers === 'object') {\n for (const [id, user] of Object.entries<any>(watchers)) {\n setDisplayName(id, user?.name);\n }\n }\n\n return map;\n}\n\n/**\n * Move caret to the very end of a contenteditable element.\n */\nexport function moveCaretToEnd(el: HTMLElement) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Move caret immediately after a specific DOM node.\n */\nexport function moveCaretAfterNode(node: Node) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Checks if a given attachment represents user-managed media (e.g., photo, video, text file, voice)\n * as opposed to backend-injected automated system cards (like linkPreviews or slash commands).\n */\nexport function isUserManagedAttachment(attachment: Attachment): boolean {\n const type = attachment.type || 'file';\n return ['image', 'video', 'file', 'voiceRecording'].includes(type);\n}\n\n/**\n * Lightweight in-memory image preloader.\n */\nconst preloadedUrls = new Set<string>();\nconst MAX_CACHE_SIZE = 500;\n\nexport function preloadImage(url: string): void {\n if (!url || preloadedUrls.has(url)) return;\n\n if (preloadedUrls.size >= MAX_CACHE_SIZE) {\n const first = preloadedUrls.values().next().value;\n if (first) preloadedUrls.delete(first);\n }\n\n const img = new Image();\n img.src = url;\n preloadedUrls.add(url);\n}\n\nexport function isImagePreloaded(url: string): boolean {\n return preloadedUrls.has(url);\n}\n\n/**\n * Format bytes into a human-readable file size (e.g. \"1.2 MB\").\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n\n/**\n * Format a date string into a relative label:\n * \"Today\", \"Yesterday\", \"Xd ago\", or \"Mon DD\" / \"Mon DD, YYYY\".\n */\nexport function formatRelativeDate(dateStr: string): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n });\n}\n\n/**\n * Get a cleaned display name from a raw file_name.\n * Strips UUID-heavy prefixes that the API sometimes prepends.\n */\nexport function getDisplayName(fileName: string): string {\n const parts = fileName.split('-');\n if (parts.length > 5) {\n const ext = fileName.split('.').pop() || '';\n return `file.${ext}`;\n }\n return fileName;\n}\n\n/**\n * Extract the hostname from a URL string. Returns the original string on error.\n */\nexport function extractDomain(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n\n/**\n * Get a human-readable preview string for the last message,\n * handling regular, system, and signal message types.\n */\nexport function getLastMessagePreview(\n channel: Channel,\n myUserId?: string,\n options?: {\n deletedMessageLabel?: React.ReactNode;\n stickerMessageLabel?: React.ReactNode;\n photoMessageLabel?: React.ReactNode;\n videoMessageLabel?: React.ReactNode;\n voiceRecordingMessageLabel?: React.ReactNode;\n fileMessageLabel?: React.ReactNode;\n encryptedMessageLabel?: React.ReactNode;\n encryptedMessageUnavailableLabel?: React.ReactNode;\n systemMessageTranslations?: SystemMessageTranslations;\n signalMessageTranslations?: SignalMessageTranslations;\n },\n): { text: React.ReactNode; user: string; timestamp?: string | Date } {\n const lastMsg = channel.state?.latestMessages?.slice(-1)[0];\n if (!lastMsg) return { text: '', user: '' };\n\n const timestamp = lastMsg.created_at;\n\n const msgType = lastMsg.type || 'regular';\n const isDeleted = isDeletedDisplayMessage(lastMsg);\n const rawText = lastMsg.text ?? '';\n const isEncrypted = lastMsg.content_type === 'mls' || Boolean((lastMsg as any).mls_ciphertext);\n\n const client = (channel as any).getClient?.() || (channel as any).client;\n const userMap = buildUserMap(channel.state, client?.state?.users);\n\n if (isDeleted) {\n return { text: options?.deletedMessageLabel || 'This message was deleted', user: '', timestamp };\n }\n\n if (msgType === 'system') {\n return { text: parseSystemMessage(rawText, userMap, options?.systemMessageTranslations), user: '', timestamp };\n }\n\n if (msgType === 'signal') {\n const result = parseSignalMessage(rawText, myUserId || '', options?.signalMessageTranslations);\n return { text: result?.text || rawText, user: '', timestamp };\n }\n\n const userId = lastMsg.user_id || '';\n const currentUser = userId && userId === myUserId ? client?.user : undefined;\n const senderName = currentUser?.name || lastMsg.user?.name || (userId && userMap[userId]) || userId || '';\n\n // Display 'Sticker' if message is a sticker\n const isSticker = msgType === 'sticker' || (lastMsg as any).sticker_url;\n if (isSticker) {\n return { text: options?.stickerMessageLabel || 'Sticker', user: senderName, timestamp };\n }\n\n // Regular / other\n let displayText: React.ReactNode = rawText;\n if (!displayText && lastMsg.attachments && lastMsg.attachments.length > 0) {\n const att = lastMsg.attachments[0];\n const type = att.type || '';\n switch (type) {\n case 'image':\n displayText = options?.photoMessageLabel || '📷 Photo';\n break;\n case 'video':\n displayText = options?.videoMessageLabel || '🎬 Video';\n break;\n case 'voiceRecording':\n displayText = options?.voiceRecordingMessageLabel || '🎤 Voice message';\n break;\n default:\n displayText = options?.fileMessageLabel || '📎 File';\n break;\n }\n if (lastMsg.attachments.length > 1) {\n if (typeof displayText === 'string') {\n displayText += ` +${lastMsg.attachments.length - 1}`;\n } else {\n const extraText = ` +${lastMsg.attachments.length - 1}`;\n displayText = React.createElement(React.Fragment, null, displayText, extraText);\n }\n }\n }\n if (!displayText && isEncrypted) {\n displayText =\n (lastMsg as any).e2ee_status === 'failed'\n ? options?.encryptedMessageUnavailableLabel || 'Encrypted message unavailable'\n : options?.encryptedMessageLabel || 'Encrypted message';\n }\n\n // Format mentions if necessary\n const lastMsgRecord = lastMsg as any;\n const mentionedUsers = lastMsgRecord.mentioned_users as string[] | undefined;\n const mentionedAll = lastMsgRecord.mentioned_all as boolean | undefined;\n\n if (\n typeof displayText === 'string' &&\n displayText &&\n (mentionedAll || (mentionedUsers && mentionedUsers.length > 0))\n ) {\n displayText = replaceMentionsForPreview(displayText, lastMsg as any, userMap);\n }\n\n return {\n text: displayText,\n user: senderName,\n timestamp,\n };\n}\n\n/**\n * Count the number of words in a string.\n * A word is defined as a non-empty sequence of characters separated by whitespace.\n */\nexport function countWords(str: string): number {\n if (!str) return 0;\n return str.trim().split(/\\s+/).filter(Boolean).length;\n}\n","export const MESSAGE_TYPES = {\n REGULAR: 'regular',\n SYSTEM: 'system',\n STICKER: 'sticker',\n SIGNAL: 'signal',\n ERROR: 'error',\n} as const;\n\nexport const ATTACHMENT_TYPES = {\n IMAGE: 'image',\n VIDEO: 'video',\n VOICE_RECORDING: 'voiceRecording',\n LINK_PREVIEW: 'linkPreview',\n FILE: 'file',\n AUDIO: 'audio',\n} as const;\n\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES] | string;\nexport type AttachmentType = (typeof ATTACHMENT_TYPES)[keyof typeof ATTACHMENT_TYPES] | string;\n\n// Helpers cho message\nexport function isSystemMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.SYSTEM;\n}\n\nexport function isStickerMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.STICKER || Boolean(message?.sticker_url);\n}\n\nexport function isRegularMessage(message: any): boolean {\n return !message?.type || message?.type === MESSAGE_TYPES.REGULAR;\n}\n\nexport function isSignalMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.SIGNAL;\n}\n\n// Helpers cho attachment\nexport function isImageAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.IMAGE;\n}\n\nexport function isVideoAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.VIDEO;\n}\n\nexport function isVoiceRecordingAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.VOICE_RECORDING;\n}\n\nexport function isLinkPreviewAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.LINK_PREVIEW;\n}\n\nexport function isImage(attachment: any): boolean {\n return Boolean(\n isImageAttachment(attachment) ||\n (!attachment?.type && (attachment?.mime_type?.startsWith('image/') || attachment?.image_url)),\n );\n}\n\nexport function isVideo(attachment: any): boolean {\n return !!(isVideoAttachment(attachment) || (!attachment.type && attachment.mime_type?.startsWith('video/')));\n}\n\nexport function isAudioAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.AUDIO;\n}\n\nexport function isAudio(attachment: any): boolean {\n return !!(\n isAudioAttachment(attachment) ||\n isVoiceRecordingAttachment(attachment) ||\n attachment.mime_type?.startsWith('audio/') ||\n attachment.file_name?.toLowerCase().endsWith('.mp3') ||\n attachment.title?.toLowerCase().endsWith('.mp3')\n );\n}\n\nexport const MESSAGE_DISPLAY_TYPES = {\n NORMAL: 'normal',\n DELETED: 'deleted',\n} as const;\n\nexport type MessageDisplayType = (typeof MESSAGE_DISPLAY_TYPES)[keyof typeof MESSAGE_DISPLAY_TYPES] | string;\n\n/** Check if a message was deleted for current user (display_type === 'deleted') */\nexport function isDeletedDisplayMessage(message: any): boolean {\n return message?.display_type === MESSAGE_DISPLAY_TYPES.DELETED;\n}\n","import { useCallback } from 'react';\nimport { useChatClient } from './useChatClient';\n\nexport const useDownloadHandler = () => {\n const { client } = useChatClient();\n\n const downloadFile = useCallback(async (url: string | undefined, filename?: string) => {\n if (!url) return;\n\n try {\n const blob = await client.downloadMedia(url);\n const urlBlob = window.URL.createObjectURL(blob);\n \n const a = document.createElement('a');\n a.style.display = 'none';\n a.href = urlBlob;\n a.download = filename || 'file';\n document.body.appendChild(a);\n \n a.click();\n \n // Cleanup after a delay to ensure the browser has started the download\n setTimeout(() => {\n if (document.body.contains(a)) {\n document.body.removeChild(a);\n }\n window.URL.revokeObjectURL(urlBlob);\n }, 1000);\n } catch (err) {\n console.warn('Download failed, falling back to new tab:', err);\n window.open(url, '_blank', 'noopener,noreferrer');\n }\n }, [client]);\n\n return { downloadFile };\n};\n","import { useContext } from 'react';\nimport { ChatContext } from '../context/ChatProvider';\nimport type { ChatContextValue } from '../context/ChatProvider';\n\nexport const useChatClient = (): ChatContextValue => {\n const ctx = useContext(ChatContext);\n if (!ctx) {\n throw new Error('useChatClient must be used within a ChatProvider');\n }\n return ctx;\n};\n","/**\n * Hash-based avatar color palette.\n *\n * Each user/channel is assigned a deterministic gradient based on\n * the hash of their name. This provides visual variety in the\n * channel list and improves readability over a single brand-color\n * fallback.\n */\n\n/** Curated gradient pairs [from, to] – all pass WCAG AA contrast with white text. */\nconst AVATAR_GRADIENTS: readonly [string, string][] = [\n ['#0EA5E9', '#38BDF8'], // Teal\n ['#10B981', '#34D399'], // Emerald\n ['#D97706', '#F59E0B'], // Amber\n ['#E11D48', '#FB7185'], // Rose\n ['#7C3AED', '#A78BFA'], // Violet\n ['#4F46E5', '#818CF8'], // Indigo\n ['#DB2777', '#F472B6'], // Pink\n ['#EA580C', '#FB923C'], // Orange\n ['#0891B2', '#22D3EE'], // Cyan\n ['#65A30D', '#A3E635'], // Lime\n] as const;\n\n/** Neutral fallback when no name is available. */\nconst FALLBACK_GRADIENT = 'linear-gradient(135deg, #6B7280 0%, #545f71 100%)';\n\n/**\n * Simple djb2-variant string hash → non-negative integer.\n */\nfunction hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash) + str.charCodeAt(i);\n hash |= 0; // Convert to 32-bit integer\n }\n return Math.abs(hash);\n}\n\n/**\n * Returns a CSS `linear-gradient(...)` string for a given name.\n * The same name always produces the same gradient (deterministic).\n */\nexport function getAvatarGradient(name?: string): string {\n if (!name) return FALLBACK_GRADIENT;\n const idx = hashString(name) % AVATAR_GRADIENTS.length;\n const [from, to] = AVATAR_GRADIENTS[idx];\n return `linear-gradient(135deg, ${from} 0%, ${to} 100%)`;\n}\n","import React, { createContext, useContext } from 'react';\nimport type { ModalProps, DropdownProps, PanelProps, ForwardMessageModalProps } from '../types';\n\nexport type ChatComponentsContextValue = {\n ModalComponent?: React.ComponentType<ModalProps>;\n DropdownComponent?: React.ComponentType<DropdownProps>;\n PanelComponent?: React.ComponentType<PanelProps>;\n ForwardMessageModalComponent?: React.ComponentType<ForwardMessageModalProps>;\n ChannelListErrorIndicator?: React.ComponentType<{ text?: string; onRetry?: () => void }>;\n};\n\nexport const ChatComponentsContext = createContext<ChatComponentsContextValue>({});\n\nexport const useChatComponents = () => useContext(ChatComponentsContext);\n","import { useState, useEffect } from 'react';\nimport { useChatClient } from './useChatClient';\nimport type { UserResponse, ExtendableGenerics, DefaultGenerics } from '@ermis-network/ermis-chat-sdk';\n\nexport const useChatUser = <ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics>() => {\n const { client } = useChatClient();\n const [user, setUser] = useState<UserResponse<ErmisChatGenerics> | undefined>(client?.user);\n\n useEffect(() => {\n if (!client) return;\n\n // Set initial user in case it changed before the effect runs\n setUser(client.user);\n\n const handleUserUpdated = (event: any) => {\n if (event.me) {\n setUser((prev) => {\n const update = { ...event.me };\n // Do not let periodic health checks wipe out the user's name/avatar with empty strings\n if (event.type === 'health.check') {\n if (!update.name) delete update.name;\n if (!update.avatar) delete update.avatar;\n }\n return { ...prev, ...update };\n });\n }\n };\n\n const listener = client.on('user.updated', handleUserUpdated);\n const healthListener = client.on('health.check', handleUserUpdated);\n\n return () => {\n listener.unsubscribe();\n healthListener.unsubscribe();\n };\n }, [client]);\n\n return { user };\n};\n","import { useEffect, useState, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isPendingMember } from '../channelRoleUtils';\nimport { isTopicChannel } from '../channelTypeUtils';\n\n/**\n * A hook that retrieves all pending invite channels from the SDK's local cache\n * without triggering an extra API network query.\n *\n * Re-renders automatically when related events (e.g., invites, accepts, deletes) arrive.\n */\nexport function useInviteChannels(): Channel[] {\n const { client } = useChatClient();\n const [updateCount, setUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!client) return;\n\n const forceUpdate = () => setUpdateCount((c) => c + 1);\n\n const handleEvent = (event: any) => {\n // If a new channel is created or we are added to it, wait for SDK initialization\n const isNewChannelEvent =\n event.type === 'member.added' ||\n event.type === 'notification.added_to_channel' ||\n event.type === 'channel.created';\n\n if (isNewChannelEvent) {\n const cid =\n event.channel?.cid ||\n event.cid ||\n (event.channel_type && event.channel_id ? `${event.channel_type}:${event.channel_id}` : null);\n\n if (cid) {\n console.log('[useInviteChannels] Received new channel event:', event.type, cid);\n let attempts = 0;\n const checkInitialized = setInterval(() => {\n attempts++;\n const channel = client.activeChannels[cid];\n if ((channel && channel.initialized) || attempts > 30) {\n console.log(\n '[useInviteChannels] Channel initialized or timeout:',\n cid,\n 'initialized:',\n channel?.initialized,\n 'attempts:',\n attempts,\n );\n clearInterval(checkInitialized);\n forceUpdate();\n }\n }, 100);\n return;\n }\n }\n setTimeout(forceUpdate, 0);\n };\n\n const listeners = [\n client.on('channels.queried', handleEvent),\n client.on('notification.invite_accepted', handleEvent),\n client.on('notification.invite_rejected', handleEvent),\n client.on('notification.invite_messaging_skipped', handleEvent),\n client.on('channel.created', handleEvent),\n client.on('channel.deleted', handleEvent),\n client.on('notification.channel_deleted', handleEvent),\n client.on('member.added', handleEvent),\n client.on('member.removed', handleEvent),\n client.on('notification.added_to_channel' as any, handleEvent),\n client.on('notification.invited' as any, handleEvent),\n ];\n\n return () => listeners.forEach((l) => l.unsubscribe());\n }, [client]);\n\n return useMemo(() => {\n if (!client) return [];\n\n return Object.values(client.activeChannels).filter((ch) => {\n // Exclude topic channels from the invites list\n if (isTopicChannel(ch)) return false;\n\n const ms = ch.state?.membership as Record<string, unknown> | undefined;\n return isPendingMember(ms?.channel_role as string);\n });\n }, [client, updateCount]);\n}\n","import type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n// ─── Group Channel Types ───────────────────────────\n// Types that behave like group/team channels (roles, capabilities, settings, topics)\nconst GROUP_CHANNEL_TYPES = new Set(['team', 'meeting']);\n\n// ─── Direct Channel Types ──────────────────────────\n// Types that behave like 1-on-1 direct messaging (block/unblock)\nconst DIRECT_CHANNEL_TYPES = new Set(['messaging']);\n\n// ─── Semantic Helpers ──────────────────────────────\n\n/** Channel supports group features: roles, capabilities, settings, topics, edit, delete */\nexport function isGroupChannel(channel: Channel | null | undefined): boolean {\n return channel ? GROUP_CHANNEL_TYPES.has(channel.type) : false;\n}\n\n/** Channel is a direct (1-on-1) conversation: block/unblock, no roles */\nexport function isDirectChannel(channel: Channel | null | undefined): boolean {\n return channel ? DIRECT_CHANNEL_TYPES.has(channel.type) : false;\n}\n\n/** Channel is a topic (sub-channel of a group channel) */\nexport function isTopicChannel(channel: Channel | null | undefined): boolean {\n return channel ? channel.type === 'topic' || Boolean(channel.data?.parent_cid) : false;\n}\n\n/** Channel is a public group that users can join without invite */\nexport function isPublicGroupChannel(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && Boolean(channel?.data?.public);\n}\n\n/** The proxy \"general\" channel of a topics-enabled group */\nexport function isGeneralProxy(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && channel?.data?.name === 'general';\n}\n\n/** Channel has topics feature enabled */\nexport function hasTopicsEnabled(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && Boolean(channel?.data?.topics_enabled);\n}\n\n/** Whether blocked state is relevant for this channel type */\nexport function supportsBlocking(channel: Channel | null | undefined): boolean {\n return isDirectChannel(channel);\n}\n","import type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from './channelTypeUtils';\n\nexport const CHANNEL_ROLES = {\n OWNER: 'owner',\n MODERATOR: 'moder',\n MEMBER: 'member',\n PENDING: 'pending',\n SKIPPED: 'skipped',\n} as const;\n\nexport type ChannelRole = typeof CHANNEL_ROLES[keyof typeof CHANNEL_ROLES] | string;\n\n/** Checks if the user is in a pending state */\nexport function isPendingMember(role?: string): boolean {\n return role === CHANNEL_ROLES.PENDING;\n}\n\n/** Checks if the user is in a skipped state (skipped a direct message invite) */\nexport function isSkippedMember(role?: string): boolean {\n return role === CHANNEL_ROLES.SKIPPED;\n}\n\n/** Checks if the user has management permissions (owner or moderator) */\nexport function canManageChannel(role?: string): boolean {\n return role === CHANNEL_ROLES.OWNER || role === CHANNEL_ROLES.MODERATOR;\n}\n\n/** Determines if the current user has the permission to remove a specific target member */\nexport function canRemoveTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n const isTargetRemovable =\n targetRole === CHANNEL_ROLES.MEMBER ||\n targetRole === CHANNEL_ROLES.PENDING ||\n (currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MODERATOR);\n \n return canManageChannel(currentUserRole) && isTargetRemovable;\n}\n\n/** Determines if the current user has the permission to ban a specific target member */\nexport function canBanTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return canRemoveTargetMember(currentUserRole, targetRole) && targetRole !== CHANNEL_ROLES.PENDING;\n}\n\n/** Determines if the current user has the permission to promote a member to moderator */\nexport function canPromoteTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MEMBER;\n}\n\n/** Determines if the current user has the permission to demote a moderator to simple member */\nexport function canDemoteTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MODERATOR;\n}\n\n/** Checks if the user is an owner of the channel */\nexport function isOwnerMember(role?: string): boolean {\n return role === CHANNEL_ROLES.OWNER;\n}\n\n/**\n * Checks if a direct channel represents a \"friend\" relationship:\n * both members must have the 'owner' channel_role.\n */\nexport function isFriendChannel(\n channel: Channel | null | undefined,\n targetUserId: string,\n currentUserId: string,\n): boolean {\n if (!channel || !isDirectChannel(channel)) return false;\n const targetMember = channel.state?.members?.[targetUserId];\n const currentMember = channel.state?.members?.[currentUserId];\n return isOwnerMember(targetMember?.channel_role as string)\n && isOwnerMember(currentMember?.channel_role as string);\n}\n","import { useEffect, useState, useMemo, useCallback } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isDirectChannel } from '../channelTypeUtils';\nimport { isOwnerMember } from '../channelRoleUtils';\n\n/**\n * A hook that retrieves all friend (contact) channels from the SDK's local cache\n * without triggering an extra API network query.\n *\n * A contact is defined as a direct (1-1) channel where both members\n * hold the 'owner' channel_role.\n *\n * Re-renders automatically when related events arrive.\n */\nexport function useContactChannels(): Channel[] {\n const { client } = useChatClient();\n const [updateCount, setUpdateCount] = useState(0);\n\n const forceUpdate = useCallback(() => setUpdateCount((c) => c + 1), []);\n\n useEffect(() => {\n if (!client) return;\n\n const listeners = [\n client.on('channels.queried', forceUpdate),\n client.on('notification.invite_accepted', forceUpdate),\n ];\n\n return () => listeners.forEach((l) => l.unsubscribe());\n }, [client, forceUpdate]);\n\n return useMemo(() => {\n if (!client) return [];\n\n return Object.values(client.activeChannels).filter((channel) => {\n if (!isDirectChannel(channel)) return false;\n\n const members = Object.values(channel.state?.members || {});\n if (members.length !== 2) return false;\n\n return members.every((m) => isOwnerMember(m.channel_role as string));\n });\n }, [client, updateCount]);\n}\n","import { useState, useEffect } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { isPendingMember } from '../channelRoleUtils';\nimport { isTopicChannel } from '../channelTypeUtils';\n\nexport const useInviteCount = () => {\n const { client } = useChatClient();\n const [inviteCount, setInviteCount] = useState(0);\n\n useEffect(() => {\n if (!client || !client.user) return;\n\n const countInvites = () => {\n let count = 0;\n const channels = Object.values(client.activeChannels);\n const userId = client.user?.id;\n if (!userId) return 0;\n for (const channel of channels) {\n // Exclude topic channels from the count\n if (isTopicChannel(channel)) continue;\n\n const membership = channel.state?.membership || channel.state?.members?.[userId];\n if (isPendingMember(membership?.channel_role as string)) {\n count++;\n }\n }\n return count;\n };\n\n // Calculate initial count\n setInviteCount(countInvites());\n\n const handleEvent = (event: any) => {\n if (\n event.type === 'channel.created' &&\n (event.user?.id === client.user?.id || event.user_id === client.user?.id)\n ) {\n return;\n }\n\n // If a new channel is created or we are added to it, wait for SDK initialization\n const isNewChannelEvent =\n event.type === 'member.added' ||\n event.type === 'notification.added_to_channel' ||\n event.type === 'channel.created';\n\n if (isNewChannelEvent) {\n const cid =\n event.channel?.cid ||\n event.cid ||\n (event.channel_type && event.channel_id ? `${event.channel_type}:${event.channel_id}` : null);\n\n if (cid) {\n console.log('[useInviteCount] Received new channel event:', event.type, cid);\n let attempts = 0;\n const checkInitialized = setInterval(() => {\n attempts++;\n const channel = client.activeChannels[cid];\n if ((channel && channel.initialized) || attempts > 30) {\n console.log(\n '[useInviteCount] Channel initialized or timeout:',\n cid,\n 'initialized:',\n channel?.initialized,\n 'attempts:',\n attempts,\n );\n clearInterval(checkInitialized);\n const newCount = countInvites();\n console.log('[useInviteCount] New invite count:', newCount);\n setInviteCount(newCount);\n }\n }, 100);\n return;\n }\n }\n\n // Delay slightly to ensure client.activeChannels is updated by SDK internal handlers first\n setTimeout(() => {\n setInviteCount(countInvites());\n }, 0);\n };\n\n const listeners = [\n client.on('channels.queried', handleEvent),\n client.on('notification.invite_accepted', handleEvent),\n client.on('notification.invite_rejected', handleEvent),\n client.on('notification.invite_messaging_skipped', handleEvent),\n client.on('channel.created', handleEvent),\n client.on('channel.deleted', handleEvent),\n client.on('notification.channel_deleted', handleEvent),\n client.on('member.added', handleEvent),\n client.on('member.removed', handleEvent),\n client.on('notification.added_to_channel' as any, handleEvent),\n client.on('notification.invited' as any, handleEvent),\n ];\n\n return () => {\n listeners.forEach((l) => l.unsubscribe());\n };\n }, [client]);\n\n return { inviteCount };\n};\n","import { useState, useEffect } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { isDirectChannel } from '../channelTypeUtils';\nimport { isOwnerMember } from '../channelRoleUtils';\n\nexport const useContactCount = () => {\n const { client } = useChatClient();\n const [contactCount, setContactCount] = useState(0);\n\n useEffect(() => {\n if (!client || !client.user) return;\n\n const countContacts = () => {\n let count = 0;\n const channels = Object.values(client.activeChannels);\n for (const channel of channels) {\n if (!isDirectChannel(channel)) continue;\n\n const members = Object.values(channel.state?.members || {});\n // Contacts are direct channels where both members are owners\n if (members.length === 2) {\n const isAllOwners = members.every((m) => isOwnerMember(m.channel_role as string));\n if (isAllOwners) count++;\n }\n }\n return count;\n };\n\n // Calculate initial count\n setContactCount(countContacts());\n\n const handleEvent = () => {\n // Delay slightly to ensure client.activeChannels is updated by SDK internal handlers first\n setTimeout(() => {\n setContactCount(countContacts());\n }, 0);\n };\n\n const listeners = [\n client.on('channels.queried', handleEvent),\n client.on('notification.invite_accepted', handleEvent),\n ];\n\n return () => {\n listeners.forEach((l) => l.unsubscribe());\n };\n }, [client]);\n\n return { contactCount };\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport type { UseChannelReturn } from '../types';\n\nexport type { UseChannelReturn } from '../types';\n\nexport const useChannel = (): UseChannelReturn => {\n const { activeChannel } = useChatClient();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n return {\n channel: activeChannel,\n loading,\n error,\n };\n};\n","import { useEffect, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isDirectChannel, isGroupChannel } from '../channelTypeUtils';\nimport { isPendingMember } from '../channelRoleUtils';\n\n/**\n * Subscribes to real-time events and keeps the channel list in sync:\n *\n * 1. `message.new` → moves channel to top, auto-calls `markRead()` if\n * the channel is currently active\n * 2. `message.read` → triggers re-render so the unread badge disappears\n *\n * The SDK already mutates `channel.state.latestMessages` and\n * `channel.state.unreadCount` before our listener fires, so we only\n * need to re-order / flush the React state.\n */\nexport function useChannelListUpdates(\n channels: Channel[],\n setChannels: React.Dispatch<React.SetStateAction<Channel[]>>,\n onOwnMessageNew?: () => void,\n): void {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n\n // Ref to always have the latest activeChannel without re-subscribing\n const activeChannelRef = useRef(activeChannel);\n activeChannelRef.current = activeChannel;\n\n // Ref to always have the latest callback without re-subscribing\n const onOwnMessageNewRef = useRef(onOwnMessageNew);\n onOwnMessageNewRef.current = onOwnMessageNew;\n\n useEffect(() => {\n // --- message.new: re-sort + auto mark-read ---\n const handleNewMessage = (event: Event) => {\n const eventCid = event.cid;\n if (!eventCid) return;\n\n const isOwnMessage = event.user?.id === client.userID;\n\n // If the new message is on the active channel and from someone else,\n // mark it as read immediately so unreadCount resets to 0.\n // Skip markRead if the current user is banned, blocked, or pending in that channel.\n const active = activeChannelRef.current;\n if (active?.cid === eventCid && !isOwnMessage) {\n const isBannedInActive = Boolean(active.state?.membership?.banned);\n const isBlockedInActive = isDirectChannel(active) && Boolean(active.state?.membership?.blocked);\n const isPendingActive = isPendingMember(active.state?.membership?.channel_role as string);\n\n if (!isBannedInActive && !isBlockedInActive && !isPendingActive) {\n active.markRead().catch(() => {\n // silently ignore mark-read errors\n });\n }\n }\n\n setChannels((prev) => {\n let targetIdx = prev.findIndex((ch) => ch.cid === eventCid);\n\n // If not found directly, check if this is a topic message — move the parent channel to top\n if (targetIdx < 0) {\n const topicChannel = client.activeChannels[eventCid];\n const parentCid = topicChannel?.data?.parent_cid as string | undefined;\n if (parentCid) {\n targetIdx = prev.findIndex((ch) => ch.cid === parentCid);\n }\n }\n\n if (targetIdx <= 0) {\n // Already at top or not found — just create a new reference\n return targetIdx === 0 ? [...prev] : prev;\n }\n\n const channel = prev[targetIdx];\n\n // Don't move banned channels to the top\n if (channel.state?.membership?.banned) {\n return [...prev];\n }\n\n // Move channel to the top\n const updated = [...prev];\n const [ch] = updated.splice(targetIdx, 1);\n updated.unshift(ch);\n return updated;\n });\n\n // Notify the component layer that the current user sent a message\n // so it can scroll to top. Use setTimeout(0) to ensure React has\n // flushed the setChannels state update before the scroll fires.\n if (isOwnMessage && onOwnMessageNewRef.current) {\n setTimeout(() => onOwnMessageNewRef.current?.(), 0);\n }\n };\n\n // --- channel.deleted: remove from list and reset active ---\n const handleChannelDeleted = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n if (!eventCid) return;\n\n if (activeChannelRef.current?.cid === eventCid) {\n setActiveChannel(null);\n }\n\n setChannels((prev) => prev.filter((ch) => ch.cid !== eventCid));\n };\n\n // --- member.removed / notification.invite_rejected: remove from list if it's current user ---\n const handleMemberRemoved = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n // channel_id is often used in notification.* events instead of .cid directly\n const normalizedCid = eventCid\n ? eventCid\n : (event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined;\n\n if (!normalizedCid) return;\n\n const removedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n\n // If the current user was removed or rejected the invite, remove the channel from their list\n if (removedUserId === client.userID) {\n if (activeChannelRef.current?.cid === normalizedCid) {\n setActiveChannel(null);\n }\n setChannels((prev) => prev.filter((ch) => ch.cid !== normalizedCid));\n }\n // Note: We don't trigger a global global re-render here if someone else is removed.\n // Individual ChannelRow components handle UI updates (e.g., via channel.updated or member.removed events locally).\n };\n\n // --- channel.created: fetch channel details and prepend to list ---\n const handleChannelCreated = async (event: Event, forceWatch: boolean = false) => {\n const type = event.channel?.type || (event as Record<string, unknown>).channel_type;\n const id = event.channel?.id || (event as Record<string, unknown>).channel_id;\n const cid = event.channel?.cid || event.cid || `${type}:${id}`;\n\n if (!type || !id) return;\n\n try {\n // Initialize or retrieve channel instance from SDK cache\n const channelInstance = client.channel(type as string, id as string);\n\n // If this is a member.added event (where event.member belongs to the current user),\n // we optimistically inject the membership so it instantly jumps into pending invites!\n // We DO NOT do this for channel.created, because in channel.created, event.member is the creator (owner).\n if (!forceWatch && event.type === 'member.added' && event.member && channelInstance.state) {\n channelInstance.state.membership = {\n ...channelInstance.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n\n // If the caller requested an explicit api call (e.g. for channel.created)\n if (forceWatch && !channelInstance.initialized) {\n await channelInstance.watch().catch((err) => console.error('Failed to watch channel:', err));\n }\n\n setChannels((prev) => {\n // Double check to prevent duplicates after async pause\n if (prev.some((c) => c.cid === cid)) {\n return prev;\n }\n return [channelInstance, ...prev];\n });\n\n // Loop wait for the core SDK to finish populating the local state from its own watch\n if (!channelInstance.initialized) {\n let attempts = 0;\n const checkInitialized = setInterval(() => {\n attempts++;\n if (channelInstance.initialized || attempts > 60 /* 3s max */) {\n clearInterval(checkInitialized);\n if (channelInstance.initialized) {\n // Force useMemo in ChannelList to recalculate classification (invite vs regular) just in case\n setChannels((p) => [...p]);\n // Manually synthesize a channel.updated event to bust the React.memo inside ChannelItem\n const clientObj = channelInstance.getClient();\n if ('dispatchEvent' in clientObj && typeof clientObj.dispatchEvent === 'function') {\n (clientObj.dispatchEvent as Function)({\n type: 'channel.updated',\n cid: channelInstance.cid,\n channel: channelInstance.data,\n });\n }\n }\n }\n }, 50);\n }\n } catch (err) {\n console.error('Failed to watch newly created channel:', err);\n }\n };\n\n // --- member.added / notification.added_to_channel: fetch if current user is added/invited ---\n const handleMemberAdded = async (event: Event) => {\n const addedUserId = event.member?.user_id || event.member?.user?.id;\n // If the current user was invited or added, fetch the channel (NO API duplication)\n if (addedUserId === client.userID) {\n await handleChannelCreated(event, false);\n }\n };\n\n // --- notification.invite_accepted / member.joined: force re-grouping or add to list ---\n const handleMemberUpdated = async (event: Event) => {\n const updatedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n if (updatedUserId === client.userID) {\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined);\n\n setChannels((prev) => {\n if (eventCid && event.member) {\n const targetChannel = prev.find((c) => c.cid === eventCid);\n if (targetChannel && targetChannel.state) {\n // Channel already in list — just update membership for re-grouping\n targetChannel.state.membership = {\n ...targetChannel.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n }\n return [...prev];\n });\n\n // For team channels with topics: re-watch to load topics from server.\n // When the user was pending, queryChannels did not return topics.\n // After accepting the invite, we need a fresh query to hydrate them.\n if (eventCid) {\n const existingChannel = client.activeChannels[eventCid];\n if (existingChannel && isGroupChannel(existingChannel) && existingChannel.data?.topics_enabled) {\n existingChannel.watch().then(() => {\n // Notify React hooks (useTopicGroupUpdates) that topics have been loaded\n existingChannel._callChannelListeners({\n type: 'channel.updated',\n cid: existingChannel.cid,\n channel: existingChannel.data,\n } as any);\n // Also trigger channel list re-render\n setChannels((p) => [...p]);\n }).catch((err) => {\n console.error('Failed to re-watch team channel after invite accepted:', err);\n });\n }\n }\n\n // If the channel is NOT in the list yet (e.g. user just joined a public channel\n // from search), add it — same logic as handleChannelCreated\n if (eventCid) {\n setChannels((prev) => {\n if (prev.some((c) => c.cid === eventCid)) return prev; // already in list\n const type = event.channel?.type || (event as Record<string, unknown>).channel_type;\n const id = event.channel?.id || (event as Record<string, unknown>).channel_id;\n if (!type || !id) return prev;\n const channelInstance = client.channel(type as string, id as string);\n if (channelInstance.state) {\n channelInstance.state.membership = {\n ...channelInstance.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n // Watch if not initialized so we get full state\n if (!channelInstance.initialized) {\n channelInstance.watch().catch(() => {});\n }\n return [channelInstance, ...prev];\n });\n }\n }\n };\n\n // --- channel.topic.enabled / disabled / created / channel.pinned / channel.unpinned: force re-render so ChannelList toggles Accordion UI, inserts new topic, or updates pinned channels ---\n const handleGenericUpdate = (event: Event) => {\n setChannels((prev) => [...prev]);\n };\n\n const sub1 = client.on('message.new', handleNewMessage);\n const sub2 = client.on('channel.deleted', handleChannelDeleted);\n const sub3 = client.on('member.removed', handleMemberRemoved);\n const sub4 = client.on('channel.created', (event) => {\n const isCreator = event.user?.id === client.userID || event.user_id === client.userID;\n handleChannelCreated(event, !isCreator);\n });\n const sub5 = client.on('member.added', handleMemberAdded);\n const sub6 = client.on('notification.added_to_channel', handleMemberAdded);\n const sub7 = client.on('notification.invite_rejected', handleMemberRemoved);\n const sub8 = client.on('notification.invite_accepted', handleMemberUpdated);\n const sub9 = client.on('channel.topic.enabled', handleGenericUpdate);\n const sub10 = client.on('channel.topic.disabled', handleGenericUpdate);\n const sub11 = client.on('channel.topic.created', handleGenericUpdate);\n const sub12 = client.on('channel.pinned', handleGenericUpdate);\n const sub13 = client.on('channel.unpinned', handleGenericUpdate);\n const sub14 = client.on('notification.invite_messaging_skipped', handleMemberUpdated);\n // When a user joins a public channel (action='join'), the server sends member.joined\n // instead of notification.invite_accepted — handle it to re-group the channel list\n const sub15 = client.on('member.joined', handleMemberUpdated);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n sub15.unsubscribe();\n };\n }, [client, setChannels, setActiveChannel]);\n}\n","import { useEffect, useState } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n/**\n * Custom hook to abstract real-time row-level updates for a single channel.\n * Manages the local unread count, last message preview, and banned status for the channel row in the list.\n */\nexport function useChannelRowUpdates(channel: Channel, currentUserId?: string) {\n // Track banned state for the current user in this channel\n const [isBannedInChannel, setIsBannedInChannel] = useState(() => Boolean(channel.state?.membership?.banned));\n const [isBlockedInChannel, setIsBlockedInChannel] = useState(() => {\n if (!isDirectChannel(channel)) return false;\n return Boolean(channel.state?.membership?.blocked);\n });\n\n // Force re-render when messages, members, or read state changes\n const [updateCount, setUpdateCount] = useState(0);\n\n useEffect(() => {\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n\n const computeIsBanned = () => {\n const selfBanned = Boolean(channel.state?.membership?.banned);\n const parentBanned = Boolean(parentChannel?.state?.membership?.banned);\n return selfBanned || parentBanned;\n };\n\n setIsBannedInChannel(computeIsBanned());\n setIsBlockedInChannel(isDirectChannel(channel) ? Boolean(channel.state?.membership?.blocked) : false);\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(true);\n }\n };\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(computeIsBanned());\n }\n };\n\n const handleUpdate = () => setUpdateCount((c) => c + 1);\n const handleE2eePreviewUpdate = (event: any) => {\n if (event?.cid === channel.cid) {\n handleUpdate();\n }\n };\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n const sub3 = channel.on('message.new', handleUpdate);\n const sub4 = channel.on('message.read', handleUpdate);\n const sub5 = channel.on('message.updated', handleUpdate);\n const sub6 = channel.on('message.deleted', handleUpdate);\n const sub6_me = channel.on('message.deleted_for_me', handleUpdate);\n const sub7 = channel.on('channel.updated', handleUpdate);\n const sub8 = channel.on('member.added', handleUpdate);\n const sub9 = channel.on('member.removed', handleUpdate);\n\n // Blocked state (messaging channels only)\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(true);\n }\n };\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(false);\n }\n };\n const sub10 = channel.on('member.blocked', handleBlocked);\n const sub11 = channel.on('member.unblocked', handleUnblocked);\n const sub12 = channel.on('channel.topic.created', handleUpdate);\n const sub13 = channel.on('channel.pinned', handleUpdate);\n const sub14 = channel.on('channel.unpinned', handleUpdate);\n const client = channel.getClient();\n const sub15 = client.on('e2ee.message_decrypted' as any, handleE2eePreviewUpdate);\n const sub16 = client.on('e2ee.local_messages_loaded' as any, handleE2eePreviewUpdate);\n const sub17 = client.on('e2ee.post_join_sync' as any, handleE2eePreviewUpdate);\n\n // Topic support: listen for ban events on parent channel too\n let sub18: { unsubscribe: () => void } | undefined;\n let sub19: { unsubscribe: () => void } | undefined;\n if (parentChannel) {\n sub18 = parentChannel.on('member.banned', handleBanned);\n sub19 = parentChannel.on('member.unbanned', handleUnbanned);\n }\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub6_me.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n sub15.unsubscribe();\n sub16.unsubscribe();\n sub17.unsubscribe();\n if (sub18) sub18.unsubscribe();\n if (sub19) sub19.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBannedInChannel, isBlockedInChannel, updateCount };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Hook that tracks whether the current user is banned in the given channel.\n *\n * Reads the initial value from `channel.state.membership.banned` and subscribes\n * to `member.banned` / `member.unbanned` WebSocket events for real-time updates.\n * If the channel is a topic, it also synchronizes with the parent channel's ban state.\n *\n * Only triggers a re-render when the *current user* is the target of the event.\n */\nexport function useBannedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBanned, setIsBanned] = useState<boolean>(() => {\n if (!channel) return false;\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n return Boolean(channel.state?.membership?.banned || parentChannel?.state?.membership?.banned);\n });\n\n useEffect(() => {\n if (!channel) {\n setIsBanned(false);\n return;\n }\n\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n\n // Sync initial state when channel changes\n setIsBanned(Boolean(channel.state?.membership?.banned || parentChannel?.state?.membership?.banned));\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBanned(true);\n }\n };\n\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n const eventCid = event.cid || (event.channel_type ? `${event.channel_type}:${event.channel_id}` : undefined);\n let cBanned = Boolean(channel.state?.membership?.banned);\n let pBanned = Boolean(parentChannel?.state?.membership?.banned);\n \n if (eventCid === channel.cid) cBanned = false;\n if (parentChannel && eventCid === parentChannel.cid) pBanned = false;\n \n setIsBanned(cBanned || pBanned);\n }\n };\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n\n let sub3: { unsubscribe: () => void } | undefined;\n let sub4: { unsubscribe: () => void } | undefined;\n\n if (parentChannel) {\n sub3 = parentChannel.on('member.banned', handleBanned);\n sub4 = parentChannel.on('member.unbanned', handleUnbanned);\n }\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n if (sub3) sub3.unsubscribe();\n if (sub4) sub4.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBanned };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n/**\n * Hook that tracks whether the current user has blocked the other party\n * in a messaging (1-1) channel.\n *\n * Reads the initial value from `channel.state.membership.blocked` and subscribes\n * to `member.blocked` / `member.unblocked` WebSocket events for real-time updates.\n *\n * Only triggers a re-render when the *current user* is the target of the event\n * (i.e., the blocker). When user A blocks user B, only A's membership has\n * `blocked: true`. B is unaffected.\n *\n * This hook is only meaningful for `messaging` channels. For `team` channels,\n * use `useBannedState` instead.\n */\nexport function useBlockedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBlocked, setIsBlocked] = useState<boolean>(() => {\n if (!isDirectChannel(channel)) return false;\n return Boolean(channel?.state?.membership?.blocked);\n });\n\n useEffect(() => {\n if (!channel || !isDirectChannel(channel)) {\n setIsBlocked(false);\n return;\n }\n\n // Sync initial state when channel changes\n setIsBlocked(Boolean(channel.state?.membership?.blocked));\n\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(true);\n }\n };\n\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(false);\n }\n };\n\n const sub1 = channel.on('member.blocked', handleBlocked);\n const sub2 = channel.on('member.unblocked', handleUnblocked);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBlocked };\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isFriendChannel } from '../channelRoleUtils';\n\nexport type OnlineStatus = 'online' | 'offline' | 'unknown';\n\n/**\n * Hook that returns the online/offline status of a specific user.\n *\n * The status is determined by checking `channel.state.watchers` on the\n * \"friend\" channel (direct channel where both members have `owner` role).\n * Real-time updates are received via `user.watching.start` and\n * `user.watching.stop` WebSocket events on that channel.\n *\n * Returns `'unknown'` if the user is not a friend (no qualifying channel found).\n *\n * @param userId – The user ID to check the online status of.\n * @param channels – The full list of loaded channels (from ChannelList).\n */\nexport function useOnlineStatus(\n userId: string | undefined,\n channels: Channel[],\n): OnlineStatus {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Find the friend channel for this user — memoized to avoid re-scans.\n const friendChannel = useMemo(() => {\n if (!userId || !currentUserId || userId === currentUserId) return null;\n return channels.find((ch) => isFriendChannel(ch, userId, currentUserId)) || null;\n }, [channels, userId, currentUserId]);\n\n // Derive initial status from watchers state.\n const [status, setStatus] = useState<OnlineStatus>(() => {\n if (!friendChannel || !userId) return 'unknown';\n return friendChannel.state?.watchers?.[userId] ? 'online' : 'offline';\n });\n\n useEffect(() => {\n if (!friendChannel || !userId) {\n setStatus('unknown');\n return;\n }\n\n // Sync initial state (in case friendChannel ref changed).\n setStatus(friendChannel.state?.watchers?.[userId] ? 'online' : 'offline');\n\n const handleWatchingStart = (event: Event) => {\n if (event.user?.id === userId) {\n setStatus('online');\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n if (event.user?.id === userId) {\n setStatus('offline');\n }\n };\n\n const sub1 = friendChannel.on('user.watching.start', handleWatchingStart);\n const sub2 = friendChannel.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [friendChannel, userId]);\n\n return status;\n}\n","import { useState, useEffect, useMemo, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isFriendChannel } from '../channelRoleUtils';\n\n/**\n * Bulk hook that returns a `Set<string>` of user IDs that are currently online.\n *\n * Only users who are \"friends\" (exist in a direct channel where both\n * members have `owner` role) are tracked. The status is derived from\n * `channel.state.watchers` and kept in sync via `user.watching.start`\n * and `user.watching.stop` WebSocket events at the **client** level\n * for efficiency (single subscription instead of N per-channel ones).\n *\n * Usage in ChannelList: `const onlineUsers = useOnlineUsers(channels);`\n * Then check: `onlineUsers.has(userId)`.\n *\n * @param channels – The full list of loaded channels (from ChannelList).\n */\nexport function useOnlineUsers(channels: Channel[]): Set<string> {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Build a map: friendUserId → Channel (the friend channel).\n // This memoizes the friend channel lookup so we only iterate once per channels change.\n const friendMap = useMemo(() => {\n const map = new Map<string, Channel>();\n if (!currentUserId) return map;\n\n for (const ch of channels) {\n const members = ch.state?.members;\n if (!members) continue;\n\n // Find the \"other\" user in this channel\n for (const memberId of Object.keys(members)) {\n if (memberId === currentUserId) continue;\n if (isFriendChannel(ch, memberId, currentUserId)) {\n map.set(memberId, ch);\n }\n }\n }\n return map;\n }, [channels, currentUserId]);\n\n // Compute the initial set of online users from watchers.\n const computeOnlineSet = (): Set<string> => {\n const set = new Set<string>();\n for (const [userId, ch] of friendMap.entries()) {\n if (ch.state?.watchers?.[userId]) {\n set.add(userId);\n }\n }\n return set;\n };\n\n const [onlineUsers, setOnlineUsers] = useState<Set<string>>(() => computeOnlineSet());\n\n // Keep friendMap in a ref so that event handlers always see the latest version.\n const friendMapRef = useRef(friendMap);\n friendMapRef.current = friendMap;\n\n // Re-compute when friendMap changes (new channels loaded, channels array mutated).\n useEffect(() => {\n setOnlineUsers(computeOnlineSet());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [friendMap]);\n\n // Subscribe at the client level for efficiency.\n useEffect(() => {\n if (!currentUserId) return;\n\n const handleWatchingStart = (event: Event) => {\n const userId = event.user?.id;\n const eventCid = event.cid;\n if (!userId || !eventCid) return;\n\n // Check if this userId belongs to a tracked friend channel\n const tracked = friendMapRef.current.get(userId);\n if (tracked && tracked.cid === eventCid) {\n setOnlineUsers((prev) => {\n if (prev.has(userId)) return prev;\n const next = new Set(prev);\n next.add(userId);\n return next;\n });\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n const userId = event.user?.id;\n const eventCid = event.cid;\n if (!userId || !eventCid) return;\n\n const tracked = friendMapRef.current.get(userId);\n if (tracked && tracked.cid === eventCid) {\n setOnlineUsers((prev) => {\n if (!prev.has(userId)) return prev;\n const next = new Set(prev);\n next.delete(userId);\n return next;\n });\n }\n };\n\n const sub1 = client.on('user.watching.start', handleWatchingStart);\n const sub2 = client.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [client, currentUserId]);\n\n return onlineUsers;\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isPendingMember } from '../channelRoleUtils';\n\n/**\n * Hook that tracks whether the current user is in a 'pending' state for the given channel.\n */\nexport function usePendingState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isPending, setIsPending] = useState<boolean>(() => {\n const membership = channel?.state?.membership || channel?.state?.members?.[currentUserId || ''];\n return isPendingMember(membership?.channel_role as string);\n });\n const [inviteUpdateCount, setInviteUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel || !currentUserId) {\n setIsPending(false);\n return;\n }\n\n const checkPending = () => {\n // Topics are accessible by default if the user is in the parent channel.\n // We ignore the individual pending invite state for topics to avoid redundant overlays.\n if (channel.type === 'topic') return false;\n\n const membership = channel.state?.membership || channel.state?.members?.[currentUserId];\n return isPendingMember(membership?.channel_role as string);\n };\n\n // Sync initial state\n setIsPending(checkPending());\n\n const defensiveUpdateState = (event: Record<string, unknown>) => {\n // The SDK does not aggressively mutate local state for all events,\n // so we manually map the incoming `member` data onto the channel state so `checkPending` sees it.\n if (event.member && channel.state && channel.state.membership) {\n channel.state.membership = {\n ...channel.state.membership,\n ...(event.member as Record<string, unknown>),\n } as unknown as Record<string, unknown>;\n }\n };\n\n const handleInviteAction = (event: Record<string, unknown>) => {\n const eventMember = event.member as Record<string, unknown>;\n const eventUser = event.user as Record<string, unknown>;\n const eventUserId = eventMember?.user_id || (eventMember?.user as Record<string, unknown>)?.id || eventUser?.id;\n\n const eventCid =\n event.cid ||\n (event.channel as Record<string, unknown>)?.cid ||\n (event.channel_id ? `${event.channel_type}:${event.channel_id}` : undefined);\n\n if (eventCid !== channel.cid) return; // Only react to events on this channel\n\n // If this event is for the current user, update their membership state\n if (eventUserId === currentUserId) {\n defensiveUpdateState(event);\n }\n\n // Re-check pending state regardless of which user triggered the event.\n // This handles both cases:\n // - Current user accepts/rejects their own invite\n // - Another user accepts an invite (hide pending-invitee box on inviter's side)\n setIsPending(checkPending());\n setInviteUpdateCount(c => c + 1);\n };\n\n const client = channel.getClient();\n const sub1 = client.on('notification.invite_accepted', handleInviteAction);\n const sub2 = client.on('notification.invite_rejected', handleInviteAction);\n const sub3 = client.on('notification.invite_messaging_skipped', handleInviteAction);\n // Public channel join sends 'member.joined' instead of 'notification.invite_accepted'\n const sub4 = client.on('member.joined', handleInviteAction);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isPending, inviteUpdateCount };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isPublicGroupChannel } from '../channelTypeUtils';\n\n/**\n * Hook that tracks whether the current user is previewing a public channel\n * without being a member.\n */\nexport function usePreviewState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isPreviewMode, setIsPreviewMode] = useState<boolean>(() => {\n if (!channel || !currentUserId || !isPublicGroupChannel(channel)) return false;\n const membership = channel?.state?.membership || channel?.state?.members?.[currentUserId];\n const isMembershipEmpty = !membership || Object.keys(membership).length === 0;\n return isMembershipEmpty;\n });\n\n useEffect(() => {\n if (!channel || !currentUserId || !isPublicGroupChannel(channel)) {\n setIsPreviewMode(false);\n return;\n }\n\n const checkPreviewMode = () => {\n const membership = channel.state?.membership || channel.state?.members?.[currentUserId];\n const isMembershipEmpty = !membership || Object.keys(membership).length === 0;\n return isMembershipEmpty;\n };\n\n // Sync initial state\n setIsPreviewMode(checkPreviewMode());\n\n const defensiveUpdateState = (event: Record<string, unknown>) => {\n if (event.member && channel.state && channel.state.membership !== undefined) {\n channel.state.membership = {\n ...channel.state.membership,\n ...(event.member as Record<string, unknown>),\n } as unknown as Record<string, unknown>;\n }\n };\n\n const handleMembershipChange = (event: Record<string, unknown>) => {\n const eventMember = event.member as Record<string, unknown>;\n const eventUser = event.user as Record<string, unknown>;\n const eventUserId = eventMember?.user_id || (eventMember?.user as Record<string, unknown>)?.id || eventUser?.id;\n\n // Only react if the event concerns the current user\n if (eventUserId !== currentUserId) return;\n\n const eventCid =\n event.cid ||\n (event.channel as Record<string, unknown>)?.cid ||\n (event.channel_id ? `${event.channel_type}:${event.channel_id}` : undefined);\n\n if (eventCid === channel.cid) {\n defensiveUpdateState(event);\n setIsPreviewMode(checkPreviewMode());\n }\n };\n\n const client = channel.getClient();\n const sub1 = client.on('member.joined', handleMembershipChange);\n\n return () => {\n sub1.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isPreviewMode };\n}\n","import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isPendingMember, isSkippedMember } from '../channelRoleUtils';\nimport { isDirectChannel } from '../channelTypeUtils';\nimport { getLastMessagePreview } from '../utils';\nimport { SystemMessageTranslations, SignalMessageTranslations } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\n/** Preview data for the most recent message across the topic group */\nexport type LatestMessagePreview = {\n text: React.ReactNode;\n user: string;\n timestamp?: string | Date;\n /** Topic name if the message came from a sub-topic, null if from general/parent */\n sourceName: string | null;\n};\n\nexport type TopicGroupUpdatesOptions = {\n deletedMessageLabel?: React.ReactNode;\n stickerMessageLabel?: React.ReactNode;\n photoMessageLabel?: React.ReactNode;\n videoMessageLabel?: React.ReactNode;\n voiceRecordingMessageLabel?: React.ReactNode;\n fileMessageLabel?: React.ReactNode;\n encryptedMessageLabel?: React.ReactNode;\n encryptedMessageUnavailableLabel?: React.ReactNode;\n systemMessageTranslations?: SystemMessageTranslations;\n signalMessageTranslations?: SignalMessageTranslations;\n};\n\n/**\n * Hook encapsulating realtime logic for a topic-enabled channel group.\n *\n * Subscribes to message and pin events on the parent channel AND all its\n * topics to compute:\n * - sorted topics list (pinned first, then by last activity)\n * - aggregated unread count across parent + all topics\n * - boolean flag indicating if any unread exists\n * - latest message preview across parent + all topics\n */\nexport function useTopicGroupUpdates(\n channel: Channel,\n currentUserId?: string,\n options?: TopicGroupUpdatesOptions\n): {\n topics: Channel[];\n aggregatedUnreadCount: number;\n hasUnread: boolean;\n updateCount: number;\n latestMessagePreview: LatestMessagePreview | null;\n} {\n const { client: chatClient, activeChannel } = useChatClient();\n const [updateCount, setUpdateCount] = useState(0);\n const bump = useCallback(() => setUpdateCount((c) => c + 1), []);\n\n // Subscribe to realtime events on parent + all topics\n useEffect(() => {\n const subs: { unsubscribe: () => void }[] = [];\n const client = channel.getClient();\n const isTopicGroupCid = (cid?: string) => {\n if (!cid) return false;\n if (cid === channel.cid) return true;\n return (channel.state?.topics || []).some((topic: Channel) => topic.cid === cid);\n };\n const handleE2eePreviewUpdate = (event: any) => {\n if (isTopicGroupCid(event?.cid)) {\n bump();\n }\n };\n\n // Parent channel events\n subs.push(channel.on('message.new', bump));\n subs.push(channel.on('message.read', bump));\n subs.push(channel.on('message.deleted', bump));\n subs.push(channel.on('channel.updated', bump));\n subs.push(channel.on('channel.topic.created', bump));\n subs.push(channel.on('channel.pinned', bump));\n subs.push(channel.on('channel.unpinned', bump));\n subs.push(client.on('e2ee.message_decrypted' as any, handleE2eePreviewUpdate));\n subs.push(client.on('e2ee.local_messages_loaded' as any, handleE2eePreviewUpdate));\n subs.push(client.on('e2ee.post_join_sync' as any, handleE2eePreviewUpdate));\n\n // Topic children events\n const currentTopics = channel.state?.topics || [];\n currentTopics.forEach((t: Channel) => {\n subs.push(t.on('message.new', bump));\n subs.push(t.on('message.read', bump));\n subs.push(t.on('message.deleted', bump));\n subs.push(t.on('channel.updated', bump));\n subs.push(t.on('channel.deleted', bump));\n subs.push(t.on('channel.pinned', bump));\n subs.push(t.on('channel.unpinned', bump));\n });\n\n return () => {\n subs.forEach((s) => s.unsubscribe());\n };\n }, [channel, channel.state?.topics, channel.state?.topics?.length, bump]);\n\n // Helper: get sort timestamp for a channel/topic\n const getTopicTime = (t: Channel): number => {\n const lastMsg = t.state?.latestMessages?.slice(-1)[0];\n if (lastMsg?.created_at) return new Date(lastMsg.created_at).getTime();\n if (t.data?.last_message_at) return new Date(t.data.last_message_at as string | Date).getTime();\n if (t.data?.created_at) return new Date(t.data.created_at as string | Date).getTime();\n return 0;\n };\n\n // Helper: check if user is excluded from unread counting\n const isExcludedUser = (ch: Channel): boolean => {\n const client = ch.getClient();\n const activeCh = client.activeChannels[ch.cid] || ch;\n const ms = activeCh.state?.membership as Record<string, unknown> | undefined;\n if (!ms) return false;\n const isBannedSelf = Boolean(ms.banned);\n \n // Topic support: check parent channel's ban status\n const parentCid = activeCh.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? client.activeChannels[parentCid] : undefined;\n const isBannedParent = Boolean(parentChannel?.state?.membership?.banned);\n \n const isBanned = isBannedSelf || isBannedParent;\n const isBlocked = isDirectChannel(activeCh) && Boolean(ms.blocked);\n const isPending = isPendingMember(ms.channel_role as string);\n const isSkipped = isSkippedMember(ms.channel_role as string);\n return isBanned || isBlocked || isPending || isSkipped;\n };\n\n // Helper: get unread count for a channel (reads from SDK state directly)\n const getUnreadCount = (ch: Channel): number => {\n if (!currentUserId || isExcludedUser(ch)) return 0;\n // Primary: use the SDK's tracked unreadCount from activeChannels to avoid stale state\n const client = ch.getClient();\n const activeCh = client.activeChannels[ch.cid] || ch;\n const state = activeCh.state as unknown as Record<string, unknown> | undefined;\n const count = (state?.unreadCount as number) ?? 0;\n return count;\n };\n\n // Sort topics: pinned first → last activity descending\n const topics = useMemo(() => {\n const allTopics = channel.state?.topics || [];\n const client = channel.getClient();\n const upToDateTopics = allTopics.map(t => client.activeChannels[t.cid] || t);\n return upToDateTopics.sort((a: Channel, b: Channel) => {\n const aPinned = a.data?.is_pinned === true;\n const bPinned = b.data?.is_pinned === true;\n if (aPinned && !bPinned) return -1;\n if (!aPinned && bPinned) return 1;\n return getTopicTime(b) - getTopicTime(a);\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel.state?.topics, updateCount]);\n\n // Aggregated unread count across parent + all topics\n const aggregatedUnreadCount = useMemo(() => {\n const client = channel.getClient();\n const activeParent = client.activeChannels[channel.cid] || channel;\n \n // Ignore the currently active channel's unread count to match UI behavior\n // where active channels don't show unread badges.\n const activeChannelCid = Object.values(client.activeChannels || {}).find(c => c.state && c.cid === activeChannel?.cid)?.cid || activeChannel?.cid;\n \n let total = 0;\n if (activeParent.cid !== activeChannelCid) {\n total += getUnreadCount(activeParent);\n }\n\n const allTopics = channel.state?.topics || [];\n allTopics.forEach((topic: Channel) => {\n const activeTopic = client.activeChannels[topic.cid] || topic;\n if (activeTopic.cid !== activeChannelCid) {\n total += getUnreadCount(activeTopic);\n }\n });\n\n return total;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel, channel.state?.topics, currentUserId, updateCount, activeChannel?.cid]);\n\n const hasUnread = aggregatedUnreadCount > 0;\n\n // Latest message preview across parent + all topics (Option B: prefix topic name)\n const latestMessagePreview = useMemo((): LatestMessagePreview | null => {\n // If banned from the main group, hide previews for all sub-items\n if (isExcludedUser(channel)) return null;\n\n const allChannels = [channel, ...(channel.state?.topics || [])];\n\n let bestTime = 0;\n let bestChannel: Channel | null = null;\n\n for (const ch of allChannels) {\n const time = getTopicTime(ch);\n if (time > bestTime) {\n bestTime = time;\n bestChannel = ch;\n }\n }\n\n if (!bestChannel) return null;\n\n const preview = getLastMessagePreview(bestChannel, currentUserId, options);\n if (!preview.text && !preview.user) return null;\n\n // sourceName is non-null only when the message comes from a sub-topic (not the parent/general)\n const isFromSubTopic = bestChannel !== channel;\n const sourceName = isFromSubTopic ? (bestChannel.data?.name as string || null) : null;\n\n return {\n text: preview.text,\n user: preview.user,\n timestamp: preview.timestamp,\n sourceName,\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n channel,\n channel.state?.topics,\n currentUserId,\n updateCount,\n options?.deletedMessageLabel,\n options?.stickerMessageLabel,\n options?.photoMessageLabel,\n options?.videoMessageLabel,\n options?.voiceRecordingMessageLabel,\n options?.fileMessageLabel,\n options?.encryptedMessageLabel,\n options?.encryptedMessageUnavailableLabel,\n options?.systemMessageTranslations,\n options?.signalMessageTranslations,\n ]);\n\n return { topics, aggregatedUnreadCount, hasUnread, updateCount, latestMessagePreview };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { isHeicFile, isVideoFile } from '@ermis-network/ermis-chat-sdk';\n\nexport function useDragAndDrop(\n onFilesDrop: (files: FileList) => void,\n disabled: boolean = false\n) {\n const [isDragging, setIsDragging] = useState(false);\n const dragCounter = useRef(0);\n\n const handleDragEnter = useCallback((e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n \n if (disabled) return;\n\n dragCounter.current += 1;\n\n // Only allow files\n if (e.dataTransfer?.items && e.dataTransfer.items.length > 0) {\n const hasFiles = Array.from(e.dataTransfer.items).some(\n (item) => item.kind === 'file'\n );\n if (hasFiles) {\n setIsDragging(true);\n }\n }\n }, [disabled]);\n\n const handleDragLeave = useCallback((e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n \n if (disabled) return;\n\n dragCounter.current -= 1;\n if (dragCounter.current === 0) {\n setIsDragging(false);\n }\n }, [disabled]);\n\n const handleDragOver = useCallback((e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n const handleDrop = useCallback((e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n \n dragCounter.current = 0;\n setIsDragging(false);\n\n if (disabled) return;\n\n if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {\n onFilesDrop(e.dataTransfer.files);\n }\n }, [disabled, onFilesDrop]);\n\n useEffect(() => {\n // Attach to the entire window so anywhere the user drags a file in the chat layout, it works\n window.addEventListener('dragenter', handleDragEnter);\n window.addEventListener('dragleave', handleDragLeave);\n window.addEventListener('dragover', handleDragOver);\n window.addEventListener('drop', handleDrop);\n\n return () => {\n window.removeEventListener('dragenter', handleDragEnter);\n window.removeEventListener('dragleave', handleDragLeave);\n window.removeEventListener('dragover', handleDragOver);\n window.removeEventListener('drop', handleDrop);\n };\n }, [handleDragEnter, handleDragLeave, handleDragOver, handleDrop]);\n\n return {\n isDragging,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { buildAttachmentPayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nexport type UseMessageSendOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n files: FilePreviewItem[];\n setFiles: React.Dispatch<React.SetStateAction<FilePreviewItem[]>>;\n hasContent: boolean;\n setHasContent: (value: boolean) => void;\n isTeamChannel: boolean;\n buildPayload: () => { text: string; mentioned_all: boolean; mentioned_users: string[] };\n reset: () => void;\n syncMessages: () => void;\n onSend?: (text: string) => void;\n onBeforeSend?: (text: string, attachments: FilePreviewItem[]) => boolean | Promise<boolean>;\n /** Message being replied to */\n quotedMessage?: FormatMessageResponse | null;\n /** Clear quoted message after send */\n clearQuotedMessage?: () => void;\n /** Message being edited */\n editingMessage?: FormatMessageResponse | null;\n /** Clear edited message after send */\n clearEditingMessage?: () => void;\n};\n\nexport function useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel,\n buildPayload,\n reset,\n syncMessages,\n onSend,\n onBeforeSend,\n quotedMessage,\n clearQuotedMessage,\n editingMessage,\n clearEditingMessage,\n}: UseMessageSendOptions) {\n const [sending, setSending] = useState(false);\n const isProcessingRef = useRef(false);\n\n const handleSend = useCallback(async () => {\n if (!activeChannel || !hasContent || sending || isProcessingRef.current) return;\n\n // Wait for all files to finish uploading\n const stillUploading = files.some((f) => f.status === 'uploading');\n if (stillUploading) return;\n\n isProcessingRef.current = true;\n\n const payload = buildPayload();\n const text = payload.text.trim();\n const isE2eeChannelForFiles =\n !!activeChannel &&\n (typeof (activeChannel as any)._isEffectiveE2ee === 'function'\n ? (activeChannel as any)._isEffectiveE2ee()\n : activeChannel.data?.mls_enabled === true);\n const uploadedFiles = files.filter((f) => f.status === 'done' || (isE2eeChannelForFiles && f.status === 'pending'));\n\n if (!text && uploadedFiles.length === 0) return;\n\n // onBeforeSend hook — return false to cancel\n if (onBeforeSend) {\n const proceed = await onBeforeSend(text, uploadedFiles);\n if (!proceed) {\n isProcessingRef.current = false;\n return;\n }\n }\n\n try {\n setSending(true);\n const isE2eeChannel =\n typeof (activeChannel as any)._isEffectiveE2ee === 'function'\n ? (activeChannel as any)._isEffectiveE2ee()\n : activeChannel.data?.mls_enabled === true;\n\n // Build attachment payloads from already-uploaded files (only applied on new messages)\n let attachments: unknown[] = [];\n let e2eeAttachmentIds: string[] | undefined;\n if (isE2eeChannel && !editingMessage && uploadedFiles.length > 0) {\n const encryptionMgr = (activeChannel as any).getClient?.().encryptionManager;\n if (!encryptionMgr?.initialized) throw new Error('E2EE attachments require an initialized encryption manager');\n const filesToUpload = uploadedFiles.map((f) => f.normalizedFile || f.file!).filter(Boolean);\n const message: Record<string, any> = { text };\n if (isTeamChannel) {\n message.mentioned_all = payload.mentioned_all;\n message.mentioned_users = payload.mentioned_users;\n }\n if (quotedMessage?.id) {\n message.quoted_message_id = quotedMessage.id;\n }\n await (activeChannel as any).enqueueE2eeAttachmentMessage(message, filesToUpload);\n syncMessages();\n\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n const errorFiles = files.filter((f) => f.status === 'error');\n setFiles(errorFiles);\n setHasContent(errorFiles.length > 0);\n reset();\n clearQuotedMessage?.();\n onSend?.(payload.text);\n activeChannel?.stopTyping();\n return;\n } else {\n attachments = uploadedFiles.map((f) => {\n if (f.originalAttachment) {\n return f.originalAttachment;\n }\n const fileObj = f.normalizedFile || f.file!;\n return buildAttachmentPayload(fileObj, f.uploadedUrl!, f.thumbUrl);\n });\n }\n\n // Build message\n const message: Record<string, any> = { text };\n\n // The API does not accept attachment arrays during standard text editing\n if (!editingMessage && attachments.length > 0) {\n message.attachments = attachments;\n }\n if (!editingMessage && e2eeAttachmentIds && e2eeAttachmentIds.length > 0) {\n message.e2ee_attachment_ids = e2eeAttachmentIds;\n }\n\n if (isTeamChannel) {\n message.mentioned_all = payload.mentioned_all;\n message.mentioned_users = payload.mentioned_users;\n }\n let sendPromise;\n\n if (editingMessage?.id) {\n sendPromise = activeChannel.editMessage(editingMessage.id, message as any);\n } else {\n if (quotedMessage?.id) {\n message.quoted_message_id = quotedMessage.id;\n }\n sendPromise = activeChannel.sendMessage(message as any);\n }\n\n // --- 0. OPTIMISTIC UI UPDATE ---\n // Instantly injects the `status: 'sending'` message scaffold from SDK into the React map\n syncMessages();\n\n // --- 1. CLEAR UI IMMEDIATELY (FIRE AND FORGET) ---\n // Clear successful files\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n\n const errorFiles = files.filter((f) => f.status === 'error');\n setFiles(errorFiles);\n setHasContent(errorFiles.length > 0);\n\n reset();\n clearQuotedMessage?.();\n clearEditingMessage?.();\n onSend?.(payload.text);\n // Stop typing indicator immediately on send\n activeChannel?.stopTyping();\n\n // --- 2. DELEGATE TO WEBSOCKET ---\n // The API call runs in background. We do not block the UI for resolution.\n // Message lists will automatically update when the backend blasts the `message.new` WS event.\n sendPromise\n .then(() => {\n // E2EE own-device WS events may arrive before the SDK replaces the\n // optimistic message with the confirmed local plaintext snapshot.\n syncMessages();\n })\n .catch((err: Error) => {\n console.error('Failed to send message over API:', err);\n // Sync React to render the SDK's internal 'status: failed' UI state\n syncMessages();\n });\n } catch (err) {\n console.error('Failed to process message send:', err);\n } finally {\n isProcessingRef.current = false;\n setSending(false);\n requestAnimationFrame(() => {\n editableRef.current?.focus();\n });\n }\n }, [\n activeChannel,\n hasContent,\n sending,\n buildPayload,\n reset,\n onSend,\n isTeamChannel,\n files,\n onBeforeSend,\n syncMessages,\n editableRef,\n setFiles,\n setHasContent,\n quotedMessage,\n clearQuotedMessage,\n editingMessage,\n clearEditingMessage,\n ]);\n\n return { sending, handleSend };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { isHeicFile, isVideoFile, normalizeFileName } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nlet _fileIdCounter = 0;\nfunction nextFileId(): string {\n return `file-${Date.now()}-${++_fileIdCounter}`;\n}\n\nexport type UseFileUploadOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useFileUpload({ activeChannel, editableRef, setHasContent }: UseFileUploadOptions) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [files, setFiles] = useState<FilePreviewItem[]>([]);\n const isE2eeChannel =\n !!activeChannel &&\n (typeof (activeChannel as any)._isEffectiveE2ee === 'function'\n ? (activeChannel as any)._isEffectiveE2ee()\n : activeChannel.data?.mls_enabled === true);\n\n /**\n * Upload a single file immediately:\n * 1. Normalize file name\n * 2. Call sendFile API\n * 3. For video: generate + upload thumbnail\n * 4. Update file item state with uploaded URL\n */\n const uploadSingleFile = useCallback(async (item: FilePreviewItem) => {\n if (!activeChannel) return;\n\n try {\n const file = item.file!;\n const normalizedName = normalizeFileName(file.name);\n const fileToUpload = normalizedName !== file.name\n ? new File([file], normalizedName, { type: file.type, lastModified: file.lastModified })\n : file;\n\n const response = await activeChannel.uploadFilePresigned(\n fileToUpload,\n fileToUpload.name,\n fileToUpload.type || 'application/octet-stream',\n (progress) => {\n setFiles((prev) =>\n prev.map((f) => (f.id === item.id ? { ...f, progress: progress.percentage } : f))\n );\n }\n );\n const uploadedUrl = response.file;\n\n let thumbUrl = '';\n if (isVideoFile(file)) {\n try {\n const thumbBlob = await activeChannel.getThumbBlobVideo(file);\n if (thumbBlob) {\n const thumbFile = new File([thumbBlob], `thumb_${normalizedName}.jpg`, { type: 'image/jpeg' });\n const thumbResp = await activeChannel.uploadFilePresigned(thumbFile, thumbFile.name, 'image/jpeg');\n thumbUrl = thumbResp.file;\n }\n } catch {\n // Thumbnail failure is non-critical\n }\n }\n\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'done' as const, uploadedUrl, thumbUrl, normalizedFile: fileToUpload }\n : f,\n ),\n );\n } catch (err: any) {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'error' as const, error: err?.message || 'Upload failed' }\n : f,\n ),\n );\n }\n }, [activeChannel]);\n\n const handleFilesSelected = useCallback((selectedFiles: FileList | null) => {\n if (!selectedFiles || selectedFiles.length === 0) return;\n\n const newItems: FilePreviewItem[] = Array.from(selectedFiles).map((file) => {\n const isPreviewable =\n (file.type.startsWith('image/') && !isHeicFile(file)) ||\n file.type.startsWith('video/');\n return {\n id: nextFileId(),\n file,\n previewUrl: isPreviewable ? URL.createObjectURL(file) : undefined,\n status: isE2eeChannel ? ('pending' as const) : ('uploading' as const),\n e2eePhase: isE2eeChannel ? ('encrypting' as const) : undefined,\n };\n });\n\n setFiles((prev) => [...prev, ...newItems]);\n setHasContent(true);\n\n if (!isE2eeChannel) {\n newItems.forEach((item) => uploadSingleFile(item));\n }\n\n // Auto-focus the input so user can press Enter to send immediately\n editableRef.current?.focus();\n }, [uploadSingleFile, setHasContent, editableRef, isE2eeChannel]);\n\n const handleRemoveFile = useCallback((id: string) => {\n setFiles((prev) => {\n const item = prev.find((f) => f.id === id);\n if (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);\n const remaining = prev.filter((f) => f.id !== id);\n const el = editableRef.current;\n const textContent = el?.textContent?.trim() ?? '';\n if (remaining.length === 0 && textContent.length === 0) {\n setHasContent(false);\n }\n return remaining;\n });\n }, [editableRef, setHasContent]);\n\n const handleAttachClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Cleanup blob URLs\n const cleanupFiles = useCallback(() => {\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n }, [files]);\n\n return {\n files,\n setFiles,\n fileInputRef,\n handleFilesSelected,\n handleRemoveFile,\n handleAttachClick,\n cleanupFiles,\n };\n}\n","import { useCallback, useState } from 'react';\nimport type { Channel, E2eeAttachmentManifest } from '@ermis-network/ermis-chat-sdk';\n\nexport type E2eeFileUploadProgress = {\n fileIndex: number;\n phase: 'generating_preview' | 'encrypting' | 'uploading' | 'completing';\n loaded: number;\n total: number;\n percentage: number;\n};\n\nexport function useE2eeFileUpload(channel: Channel | null) {\n const [progress, setProgress] = useState<E2eeFileUploadProgress | null>(null);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<string | undefined>();\n\n const upload = useCallback(\n async (files: Blob[]): Promise<{ attachments: E2eeAttachmentManifest[]; e2ee_attachment_ids: string[] }> => {\n if (!channel) return { attachments: [], e2ee_attachment_ids: [] };\n const manager = (channel as any).getClient?.().encryptionManager;\n if (!manager?.initialized) throw new Error('E2EE attachments require an initialized encryption manager');\n setUploading(true);\n setError(undefined);\n try {\n return await manager.uploadE2eeAttachments(channel.type, channel.id, files, { onProgress: setProgress });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n throw err;\n } finally {\n setUploading(false);\n }\n },\n [channel],\n );\n\n return { upload, progress, uploading, error };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport type { Channel, E2eeAttachmentManifest, E2eeAttachmentTransferProgress } from '@ermis-network/ermis-chat-sdk';\n\nexport const E2EE_PREVIEW_MAX_CONCURRENT = 3;\nexport const E2EE_PREVIEW_CACHE_LIMIT = 100;\n\nconst previewObjectUrlCache = new Map<string, { url: string; blob: Blob }>();\n\nexport function clearE2eePreviewObjectUrlCache(): void {\n for (const value of previewObjectUrlCache.values()) {\n URL.revokeObjectURL(value.url);\n }\n previewObjectUrlCache.clear();\n}\n\nexport type E2eeAttachmentRenderState = {\n url?: string;\n blob?: Blob;\n loading: boolean;\n error?: string;\n progress?: E2eeAttachmentTransferProgress;\n load: () => Promise<string | undefined>;\n download: (filename?: string) => Promise<void>;\n streamUrl?: string;\n streamLoading: boolean;\n loadStream: () => Promise<string | undefined>;\n disposeStream: () => Promise<void>;\n revoke: () => void;\n};\n\nfunction manifestDisplayString(\n manifest: E2eeAttachmentManifest,\n kind: 'original' | 'preview',\n key: string,\n): string | undefined {\n const asset = manifest.assets.find((item) => item.kind === kind) || manifest.assets[0];\n const value = asset?.display?.[key];\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction previewCacheKey(\n channel: Channel,\n manifest: E2eeAttachmentManifest,\n kind: 'original' | 'preview',\n): string | undefined {\n if (kind !== 'preview') return undefined;\n const asset = manifest.assets.find((item) => item.kind === 'preview');\n if (!asset) return undefined;\n const cid = (channel as any).cid || (channel as any).data?.cid || `${channel.type}:${channel.id}`;\n return `${cid}:${manifest.attachment_id}:${asset.asset_id}`;\n}\n\nfunction cachePreviewObjectUrl(key: string, url: string, blob: Blob): void {\n if (previewObjectUrlCache.has(key)) {\n const existing = previewObjectUrlCache.get(key);\n if (existing) URL.revokeObjectURL(existing.url);\n previewObjectUrlCache.delete(key);\n }\n previewObjectUrlCache.set(key, { url, blob });\n while (previewObjectUrlCache.size > E2EE_PREVIEW_CACHE_LIMIT) {\n const oldestKey = previewObjectUrlCache.keys().next().value;\n if (!oldestKey) break;\n const oldest = previewObjectUrlCache.get(oldestKey);\n if (oldest) URL.revokeObjectURL(oldest.url);\n previewObjectUrlCache.delete(oldestKey);\n }\n}\n\nexport function useE2eeAttachmentRenderer(\n channel: Channel | null,\n manifest?: E2eeAttachmentManifest,\n kind: 'original' | 'preview' = 'original',\n): E2eeAttachmentRenderState {\n const [url, setUrl] = useState<string | undefined>();\n const [blob, setBlob] = useState<Blob | undefined>();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | undefined>();\n const [progress, setProgress] = useState<E2eeAttachmentTransferProgress | undefined>();\n const [streamUrl, setStreamUrl] = useState<string | undefined>();\n const [streamLoading, setStreamLoading] = useState(false);\n const streamDisposeRef = useRef<(() => Promise<void>) | undefined>(undefined);\n const cachedPreviewRef = useRef(false);\n\n const disposeStream = useCallback(async () => {\n const dispose = streamDisposeRef.current;\n streamDisposeRef.current = undefined;\n setStreamUrl(undefined);\n if (dispose) await dispose();\n }, []);\n\n const revoke = useCallback(() => {\n setUrl((current) => {\n if (current && !(kind === 'preview' && cachedPreviewRef.current)) URL.revokeObjectURL(current);\n return undefined;\n });\n setBlob(undefined);\n setProgress(undefined);\n cachedPreviewRef.current = false;\n void disposeStream();\n }, [disposeStream, kind]);\n\n const load = useCallback(async () => {\n if (!channel || !manifest) return undefined;\n if (url) return url;\n const cacheKey = previewCacheKey(channel, manifest, kind);\n if (cacheKey) {\n const cached = previewObjectUrlCache.get(cacheKey);\n if (cached) {\n previewObjectUrlCache.delete(cacheKey);\n previewObjectUrlCache.set(cacheKey, cached);\n cachedPreviewRef.current = true;\n setBlob(cached.blob);\n setUrl(cached.url);\n return cached.url;\n }\n }\n const manager = (channel as any).getClient?.().encryptionManager;\n if (!manager?.initialized) {\n setError('E2EE is not initialized');\n return undefined;\n }\n setLoading(true);\n setError(undefined);\n setProgress(undefined);\n try {\n const downloaded = await manager.downloadE2eeAttachmentAsset(channel.type, channel.id, manifest, kind, {\n onProgress: setProgress,\n });\n const mimeType = manifestDisplayString(manifest, kind, 'mime_type');\n const typedBlob =\n mimeType && downloaded.type !== mimeType ? new Blob([downloaded], { type: mimeType }) : downloaded;\n const objectUrl = URL.createObjectURL(typedBlob);\n if (cacheKey) {\n cachePreviewObjectUrl(cacheKey, objectUrl, typedBlob);\n cachedPreviewRef.current = true;\n } else {\n cachedPreviewRef.current = false;\n }\n setBlob(typedBlob);\n setUrl(objectUrl);\n return objectUrl;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n return undefined;\n } finally {\n setLoading(false);\n }\n }, [channel, kind, manifest, url]);\n\n const loadStream = useCallback(async () => {\n if (!channel || !manifest || kind !== 'original') return undefined;\n if (streamUrl) return streamUrl;\n const manager = (channel as any).getClient?.().encryptionManager;\n if (!manager?.initialized || typeof manager.createE2eeAttachmentStreamUrl !== 'function') return undefined;\n setStreamLoading(true);\n setError(undefined);\n try {\n const handle = await manager.createE2eeAttachmentStreamUrl(channel.type, channel.id, manifest, 'original');\n if (!handle?.url) return undefined;\n streamDisposeRef.current = handle.dispose;\n setStreamUrl(handle.url);\n return handle.url;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n return undefined;\n } finally {\n setStreamLoading(false);\n }\n }, [channel, kind, manifest, streamUrl]);\n\n const download = useCallback(\n async (filename?: string) => {\n const objectUrl = await load();\n if (!objectUrl || typeof document === 'undefined') return;\n const anchor = document.createElement('a');\n anchor.href = objectUrl;\n anchor.download =\n filename || (manifest ? manifestDisplayString(manifest, kind, 'name') : undefined) || 'encrypted-attachment';\n document.body.appendChild(anchor);\n anchor.click();\n anchor.remove();\n },\n [kind, load, manifest],\n );\n\n useEffect(() => revoke, [revoke]);\n\n return {\n url,\n blob,\n streamUrl,\n streamLoading,\n loading,\n error,\n progress,\n load,\n loadStream,\n download,\n disposeStream,\n revoke,\n };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { PendingE2eeSendRecord } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\nexport function usePendingE2eeSends(statuses?: string[]) {\n const { client } = useChatClient();\n const [records, setRecords] = useState<PendingE2eeSendRecord[]>([]);\n const [loading, setLoading] = useState(false);\n\n const refresh = useCallback(async () => {\n const storage = client.encryptionManager?.storage;\n if (!storage?.listPendingE2eeSends) {\n setRecords([]);\n return;\n }\n setLoading(true);\n try {\n setRecords(await storage.listPendingE2eeSends(statuses));\n } finally {\n setLoading(false);\n }\n }, [client.encryptionManager, JSON.stringify(statuses || [])]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n return { records, loading, refresh };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { moveCaretToEnd } from '../utils';\n\nexport type UseEmojiPickerOptions = {\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useEmojiPicker({ editableRef, setHasContent }: UseEmojiPickerOptions) {\n const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);\n const savedRangeRef = useRef<Range | null>(null);\n\n const handleEmojiSelect = useCallback((emoji: string) => {\n const el = editableRef.current;\n if (!el) return;\n\n // Restore saved cursor position, or move to end\n el.focus();\n const sel = window.getSelection();\n if (sel && savedRangeRef.current) {\n sel.removeAllRanges();\n sel.addRange(savedRangeRef.current);\n savedRangeRef.current = null;\n } else {\n moveCaretToEnd(el);\n }\n\n document.execCommand('insertText', false, emoji + ' ');\n setHasContent(true);\n setEmojiPickerOpen(false);\n }, [editableRef, setHasContent]);\n\n const handleEmojiClose = useCallback(() => {\n setEmojiPickerOpen(false);\n savedRangeRef.current = null;\n }, []);\n\n const toggleEmojiPicker = useCallback(() => {\n // Save current cursor position before picker steals focus\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0) {\n savedRangeRef.current = sel.getRangeAt(0).cloneRange();\n }\n setEmojiPickerOpen((prev) => !prev);\n }, []);\n\n return {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\nexport type UseStickerPickerOptions = {\n activeChannel?: Channel | null;\n stickerIframeUrl?: string;\n};\n\nexport function useStickerPicker({\n activeChannel,\n stickerIframeUrl = 'https://sticker.ermis.network',\n}: UseStickerPickerOptions) {\n const [stickerPickerOpen, setStickerPickerOpen] = useState(false);\n\n const toggleStickerPicker = useCallback(() => {\n setStickerPickerOpen((prev) => !prev);\n }, []);\n\n const closeStickerPicker = useCallback(() => {\n setStickerPickerOpen(false);\n }, []);\n\n const handleStickerSend = useCallback(\n async (stickerUrl: string) => {\n if (!activeChannel) return;\n try {\n await activeChannel.sendMessage({\n text: '',\n attachments: [],\n sticker_url: stickerUrl,\n });\n setStickerPickerOpen(false);\n } catch (error) {\n console.error('Failed to send sticker', error);\n }\n },\n [activeChannel],\n );\n\n useEffect(() => {\n if (!stickerPickerOpen) return;\n\n const handleMessage = (event: MessageEvent) => {\n const stickerUrl = event.data?.data?.content?.url;\n if (!stickerUrl || typeof stickerUrl !== 'string') return;\n const fullUrl = `${stickerIframeUrl}/${stickerUrl}`;\n handleStickerSend(fullUrl);\n };\n\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [stickerPickerOpen, stickerIframeUrl, handleStickerSend]);\n\n return {\n stickerPickerOpen,\n toggleStickerPicker,\n closeStickerPicker,\n handleStickerSend,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { usePreviewState } from './usePreviewState';\nimport { isGroupChannel } from '../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../channelRoleUtils';\n\nexport const useChannelCapabilities = () => {\n const { activeChannel, client } = useChatClient();\n const [updateTick, setUpdateTick] = useState(0);\n\n // Real-time synchronization for channel adjustments\n useEffect(() => {\n if (!activeChannel) return;\n const handleUpdate = () => setUpdateTick(t => t + 1);\n \n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const currentUserId = client?.userID || '';\n const { isPreviewMode } = usePreviewState(activeChannel, currentUserId);\n const isGroupCh = isGroupChannel(activeChannel);\n const role = (activeChannel?.state as any)?.members?.[currentUserId]?.channel_role;\n \n const isOwner = isPreviewMode ? false : (role === CHANNEL_ROLES.OWNER || activeChannel?.data?.created_by_id === currentUserId);\n const isModerator = isPreviewMode ? false : (role === CHANNEL_ROLES.MODERATOR);\n const isOwnerOrModerator = isOwner || isModerator || (!isPreviewMode && canManageChannel(role));\n\n const capabilities: string[] = isGroupCh ? (activeChannel?.data as any)?.member_capabilities || [] : [];\n\n const hasCapability = useCallback((cap: string) => {\n if (isPreviewMode) return false;\n return !isGroupCh || isOwnerOrModerator || capabilities.includes(cap);\n }, [isGroupCh, isOwnerOrModerator, capabilities, updateTick, isPreviewMode]);\n\n return {\n isGroupChannel: isGroupCh,\n isOwner,\n isModerator,\n isOwnerOrModerator,\n hasCapability,\n role,\n capabilities\n };\n};\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\nexport const useChannelMembers = (channel: Channel | null | undefined) => {\n const [memberUpdateCount, setMemberUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateMembers = () => setMemberUpdateCount(c => c + 1);\n\n const sub1 = channel.on('member.added', updateMembers);\n const sub2 = channel.on('member.removed', updateMembers);\n const sub3 = channel.on('member.updated', updateMembers);\n const sub4 = channel.on('member.promoted', updateMembers);\n const sub5 = channel.on('member.demoted', updateMembers);\n const sub6 = channel.on('member.banned', updateMembers);\n const sub7 = channel.on('member.unbanned', updateMembers);\n const sub8 = channel.on('notification.invite_rejected', updateMembers);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n };\n }, [channel]);\n\n const membersArray = useMemo(() => {\n if (!channel?.state?.members) return [];\n return Object.values(channel.state.members) as Array<Record<string, unknown>>;\n }, [channel?.state?.members, memberUpdateCount]);\n\n return { members: membersArray, memberUpdateCount };\n};\n\nexport const useChannelProfile = (channel: Channel | null | undefined) => {\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateChannel = () => setChannelUpdateCount(c => c + 1);\n const sub1 = channel.on('channel.updated', updateChannel);\n const sub2 = channel.on('channel.pinned', updateChannel);\n const sub3 = channel.on('channel.unpinned', updateChannel);\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n };\n }, [channel]);\n\n const channelName = useMemo(() => channel?.data?.name || channel?.cid || 'Unknown Channel', [channel?.data?.name, channel?.cid, channel?.type, channelUpdateCount]);\n const channelImage = useMemo(() => channel?.data?.image as string | undefined, [channel?.data?.image, channelUpdateCount]);\n const channelDescription = useMemo(() => channel?.data?.description as string | undefined, [channel?.data?.description, channelUpdateCount]);\n const isPinned = useMemo(() => channel?.data?.is_pinned === true, [channel?.data?.is_pinned, channelUpdateCount]);\n\n return { channelName, channelImage, channelDescription, isPinned };\n};\n","import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react';\nimport { VList as _VList, type VListHandle } from 'virtua';\nconst VList = _VList as any;\nimport type { Channel, Event, ChannelFilters } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChannelListUpdates } from '../hooks/useChannelListUpdates';\nimport { useOnlineUsers } from '../hooks/useOnlineUsers';\nimport { getLastMessagePreview } from '../utils';\nimport { useChannelRowUpdates } from '../hooks/useChannelRowUpdates';\nimport { usePendingState } from '../hooks/usePendingState';\nimport {\n SystemMessageTranslations,\n SignalMessageTranslations,\n} from '@ermis-network/ermis-chat-sdk';\nimport { Avatar } from './Avatar';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport type { ChannelItemProps, ChannelListProps } from '../types';\n\nexport type { ChannelListProps, ChannelItemProps } from '../types';\nimport type { ChannelActionsProps } from '../types';\nimport { TopicModal } from './TopicModal';\nimport { DefaultChannelActions, computeDefaultActions } from './ChannelActions';\nimport { FlatTopicGroupItem } from './FlatTopicGroupItem';\nimport { isDirectChannel, isGroupChannel, hasTopicsEnabled } from '../channelTypeUtils';\nimport { canManageChannel, isPendingMember, isSkippedMember, isFriendChannel } from '../channelRoleUtils';\n\nexport { DefaultChannelActions } from './ChannelActions';\nexport type { ChannelAction, ChannelActionsProps } from '../types';\n\n\n\n/* ----------------------------------------------------------\n Memoized channel list item (exported for consumer reuse)\n ---------------------------------------------------------- */\nexport const ChannelItem: React.FC<ChannelItemProps> = React.memo(({\n channel,\n isActive,\n hasUnread,\n unreadCount,\n lastMessageText,\n lastMessageUser,\n lastMessageTimestamp,\n onSelect,\n AvatarComponent,\n isBlocked,\n isPending,\n pendingBadgeLabel,\n blockedBadgeLabel,\n isClosedTopic,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n onDeleteTopic,\n onTruncateChannel,\n hiddenActions,\n actionLabels,\n actionIcons,\n isOnline,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Subscribe to channel.updated so that when name/image/description change,\n // we re-render from within (bypasses React.memo which only blocks parent-driven re-renders)\n const [updateCount, forceUpdate] = useState(0);\n useEffect(() => {\n const handleUpdate = () => forceUpdate((c) => c + 1);\n const sub1 = channel.on('channel.updated', handleUpdate);\n const sub2 = channel.on('channel.pinned', handleUpdate);\n const sub3 = channel.on('channel.unpinned', handleUpdate);\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n };\n }, [channel]);\n\n const defaultActions = useMemo(\n () => computeDefaultActions(channel, currentUserId, { onAddTopic, onEditTopic, onToggleCloseTopic, onDeleteTopic, onTruncateChannel, isBlocked, actionLabels, actionIcons }),\n [channel, currentUserId, updateCount, onAddTopic, onEditTopic, onToggleCloseTopic, onDeleteTopic, onTruncateChannel, isBlocked, actionLabels, actionIcons],\n );\n\n const filteredActions = useMemo(() => {\n if (!hiddenActions || hiddenActions.length === 0) return defaultActions;\n return defaultActions.filter(a => !hiddenActions.includes(a.id));\n }, [defaultActions, hiddenActions]);\n const ActionsComponent = ChannelActionsComponent || DefaultChannelActions;\n\n // For DM channels, resolve name/image from the other member if channel.data.name is missing\n const resolvedNameImage = useMemo(() => {\n if (channel.data?.name) {\n return { name: channel.data.name as string, image: channel.data.image as string | undefined };\n }\n // For DM (messaging) channels, find the other member's info\n if (isDirectChannel(channel) && currentUserId && channel.state?.members) {\n const members = Object.values(channel.state.members) as any[];\n const other = members.find((m: any) => (m.user_id || m.user?.id) !== currentUserId);\n if (other) {\n const otherUser = other.user || other;\n return {\n name: otherUser.name || otherUser.id || channel.cid,\n image: otherUser.image || otherUser.avatar || otherUser.avatar_url,\n };\n }\n }\n return { name: channel.cid, image: channel.data?.image as string | undefined };\n }, [channel.data?.name, channel.data?.image, channel.state?.members, currentUserId, channel.cid, updateCount]);\n\n const name = resolvedNameImage.name;\n const image = resolvedNameImage.image;\n const showUnread = hasUnread && !isActive;\n const avatarClassName = isGroupChannel(channel) ? 'ermis-avatar-wrapper--group' : undefined;\n\n const timestampText = useMemo(() => {\n if (!lastMessageTimestamp) return null;\n const d = new Date(lastMessageTimestamp);\n if (isNaN(d.getTime())) return null;\n const today = new Date();\n const isToday = d.toDateString() === today.toDateString();\n return isToday\n ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n : d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }, [lastMessageTimestamp]);\n\n const handleClick = useCallback(() => {\n onSelect(channel);\n }, [channel, onSelect]);\n\n const itemClass = [\n 'ermis-channel-list__item',\n isActive ? 'ermis-channel-list__item--active' : '',\n showUnread ? 'ermis-channel-list__item--unread' : '',\n isPending ? 'ermis-channel-list__item--pending' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} onClick={handleClick}>\n <div className=\"ermis-channel-list__item-avatar-wrapper\">\n <AvatarComponent image={image} name={name} size={45} disableLightbox className={avatarClassName} />\n {isOnline !== undefined && (\n <span className={`ermis-channel-list__online-dot ermis-channel-list__online-dot--${isOnline ? 'online' : 'offline'}`} />\n )}\n {showUnread && unreadCount > 0 && (\n <span className=\"ermis-channel-list__avatar-unread-badge\">\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n </div>\n <div className=\"ermis-channel-list__item-content\">\n <div className=\"ermis-channel-list__item-top-row\">\n <div className=\"ermis-channel-list__item-name\">{name}</div>\n {channel.data?.is_pinned === true && !isClosedTopic && PinnedIconComponent && (\n <span className=\"ermis-channel-list__pinned-icon\" title=\"Pinned\">\n <PinnedIconComponent />\n </span>\n )}\n {isClosedTopic && (\n <span className=\"ermis-channel-list__closed-icon\">\n {closedTopicIcon || (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n </span>\n )}\n {!isClosedTopic && timestampText && <div className=\"ermis-channel-list__item-timestamp\">{timestampText}</div>}\n\n {isPending && (\n <span className=\"ermis-channel-list__pending-badge\">{pendingBadgeLabel || 'Invited'}</span>\n )}\n\n {isBlocked && (\n <span className=\"ermis-channel-list__blocked-icon\" title={blockedBadgeLabel || \"Blocked\"}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </span>\n )}\n </div>\n <div className=\"ermis-channel-list__item-bottom-row\">\n {!isClosedTopic && lastMessageText && (\n <div className=\"ermis-channel-list__item-last-message\">\n {lastMessageUser && (\n <span className=\"ermis-channel-list__item-last-message-user\">\n {lastMessageUser}:{' '}\n </span>\n )}\n <span>{lastMessageText}</span>\n </div>\n )}\n\n {!isClosedTopic && (\n <div className=\"ermis-channel-list__item-badges\">\n {showUnread && unreadCount > 0 && (\n <span className=\"ermis-channel-list__unread-badge\">\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n {!isPending && (\n <div className=\"ermis-channel-list__item-actions-wrapper\">\n <ActionsComponent channel={channel} actions={filteredActions} onClose={() => { }} />\n </div>\n )}\n </div>\n );\n});\nChannelItem.displayName = 'ChannelItem';\n\nexport const DefaultPinnedIcon = React.memo(() => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n));\nDefaultPinnedIcon.displayName = 'DefaultPinnedIcon';\n\nconst DefaultLoading = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__loading\">{text || 'Loading channels...'}</div>\n));\nDefaultLoading.displayName = 'DefaultLoading';\n\nconst DefaultEmpty = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__empty\">{text || 'No channels found'}</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\nconst DefaultError = React.memo(({ text, onRetry }: { text?: string; onRetry?: () => void }) => (\n <div className=\"ermis-channel-list__error\">\n <div className=\"ermis-channel-list__error-icon\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n </div>\n <div className=\"ermis-channel-list__error-text\">{text || 'Failed to load channels'}</div>\n {onRetry && (\n <button className=\"ermis-channel-list__error-retry\" onClick={onRetry}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ marginRight: '6px' }}>\n <path d=\"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n </svg>\n Retry\n </button>\n )}\n </div>\n));\nDefaultError.displayName = 'DefaultError';\n\n/* ----------------------------------------------------------\n Virtual Row Component to map channel and defer parsing\n ---------------------------------------------------------- */\ntype ChannelRowProps = {\n channel: Channel;\n isActive: boolean;\n handleSelect: (c: Channel) => void;\n renderChannel?: (c: Channel, active: boolean) => React.ReactNode;\n ChannelItemComponent: React.ComponentType<ChannelItemProps>;\n AvatarComponent: React.ComponentType<any>;\n currentUserId?: string;\n pendingBadgeLabel?: string;\n blockedBadgeLabel?: string;\n closedTopicIcon?: React.ReactNode;\n PinnedIconComponent?: React.ComponentType;\n ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;\n onAddTopic?: (channel: Channel) => void;\n onEditTopic?: (channel: Channel) => void;\n onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;\n onDeleteTopic?: (channel: Channel) => void;\n onTruncateChannel?: (channel: Channel) => void;\n hiddenActions?: string[];\n actionLabels?: import('../types').ChannelActionLabels;\n actionIcons?: import('../types').ChannelActionIcons;\n isOnline?: boolean;\n deletedMessageLabel?: React.ReactNode;\n stickerMessageLabel?: React.ReactNode;\n photoMessageLabel?: React.ReactNode;\n videoMessageLabel?: React.ReactNode;\n voiceRecordingMessageLabel?: React.ReactNode;\n fileMessageLabel?: React.ReactNode;\n encryptedMessageLabel?: React.ReactNode;\n encryptedMessageUnavailableLabel?: React.ReactNode;\n systemMessageTranslations?: SystemMessageTranslations;\n signalMessageTranslations?: SignalMessageTranslations;\n};\n\nexport const ChannelRow: React.FC<ChannelRowProps> = React.memo(({\n channel,\n isActive,\n handleSelect,\n renderChannel,\n ChannelItemComponent,\n AvatarComponent,\n currentUserId,\n pendingBadgeLabel,\n blockedBadgeLabel,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n onDeleteTopic,\n onTruncateChannel,\n hiddenActions,\n actionLabels,\n actionIcons,\n isOnline,\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n encryptedMessageLabel,\n encryptedMessageUnavailableLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n}) => {\n // Use the new custom hook to handle all row-level realtime updates\n const { isBannedInChannel, isBlockedInChannel, updateCount } = useChannelRowUpdates(channel, currentUserId);\n const { isPending } = usePendingState(channel, currentUserId);\n const isSkipped = isSkippedMember(channel.state?.membership?.channel_role as string);\n\n const channelState = channel.state as unknown as Record<string, unknown> | undefined;\n const rawUnreadCount = (channelState?.unreadCount as number) ?? 0;\n\n const isClosedTopic = channel.data?.is_closed_topic === true;\n\n // Render logic continues...\n const unreadCount = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? 0 : rawUnreadCount;\n const hasUnread = unreadCount > 0;\n\n // Derive last message preview computation\n const { text: rawLastMessageText, user: rawLastMessageUser, timestamp: rawLastMessageTimestamp } = useMemo(\n () =>\n getLastMessagePreview(channel, currentUserId, {\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n encryptedMessageLabel,\n encryptedMessageUnavailableLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n }),\n // Recompute if latestMessage changes or we get a force update\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n channel,\n channel.state?.latestMessages,\n updateCount,\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n encryptedMessageLabel,\n encryptedMessageUnavailableLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n ]\n );\n\n // Hide last message preview when banned, blocked, pending or skipped\n const lastMessageText = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? '' : rawLastMessageText;\n const lastMessageUser = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped || isDirectChannel(channel)) ? '' : rawLastMessageUser;\n const lastMessageTimestamp = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? null : rawLastMessageTimestamp;\n\n if (renderChannel) {\n return (\n <div onClick={() => handleSelect(channel)}>\n {renderChannel(channel, isActive)}\n </div>\n );\n }\n\n return (\n <ChannelItemComponent\n channel={channel}\n isActive={isActive}\n hasUnread={hasUnread}\n unreadCount={unreadCount}\n lastMessageText={lastMessageText}\n lastMessageUser={lastMessageUser}\n lastMessageTimestamp={lastMessageTimestamp}\n onSelect={handleSelect}\n AvatarComponent={AvatarComponent}\n isBlocked={isBlockedInChannel}\n isPending={isPending}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n isClosedTopic={isClosedTopic}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={onAddTopic}\n onEditTopic={onEditTopic}\n onToggleCloseTopic={onToggleCloseTopic}\n onDeleteTopic={onDeleteTopic}\n onTruncateChannel={onTruncateChannel}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={isOnline}\n />\n );\n});\nChannelRow.displayName = 'ChannelRow';\n\n\nexport const ChannelList: React.FC<ChannelListProps> = React.memo(({\n filters = { type: ['messaging', 'team', 'meeting'], include_hidden_messages: true } as unknown as ChannelFilters,\n sort = [],\n options = { message_limit: 1 } as unknown as ChannelListProps['options'],\n renderChannel,\n onChannelSelect,\n className,\n LoadingIndicator = DefaultLoading,\n EmptyStateIndicator = DefaultEmpty,\n ErrorIndicator,\n AvatarComponent = Avatar,\n ChannelItemComponent = ChannelItem,\n pendingInvitesLabel,\n channelsLabel = 'Channels',\n pendingBadgeLabel,\n loadingLabel,\n emptyStateLabel = 'No channels found',\n errorLabel = 'Failed to load channels',\n blockedBadgeLabel = 'Blocked',\n onAddTopic,\n TopicEmojiPickerComponent,\n closedTopicIcon,\n PinnedIconComponent = DefaultPinnedIcon,\n ChannelActionsComponent,\n onEditTopic,\n onToggleCloseTopic,\n onDeleteTopic,\n onTruncateChannel,\n hiddenActions,\n actionLabels,\n actionIcons,\n showOnlineStatus = true,\n showPendingInvites = true,\n onTopicDrillDown,\n maxVisibleTopics,\n moreTopicsLabel,\n generalTopicLabel = 'general',\n TopicPillComponent,\n FlatTopicGroupItemComponent,\n scrollToTopOnOwnMessage = true,\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n encryptedMessageLabel,\n encryptedMessageUnavailableLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n showTopicPills = false,\n}) => {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n const { ChannelListErrorIndicator } = useChatComponents();\n\n const [channels, setChannels] = useState<Channel[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<any>(null);\n\n const ActualErrorIndicator = ErrorIndicator || ChannelListErrorIndicator || DefaultError;\n const [isPendingExpanded, setIsPendingExpanded] = useState(true);\n const [addingTopicForChannel, setAddingTopicForChannel] = useState<Channel | null>(null);\n const [editingTopicForChannel, setEditingTopicForChannel] = useState<Channel | null>(null);\n\n // Ref for imperative scroll control on the virtualized list\n const vlistRef = useRef<VListHandle>(null);\n\n // Scroll to top when the current user sends a message\n const handleOwnMessageNew = useCallback(() => {\n vlistRef.current?.scrollToIndex(0);\n }, []);\n\n const handleAddTopicClick = useCallback((channel: Channel) => {\n if (onAddTopic) {\n onAddTopic(channel);\n } else {\n setAddingTopicForChannel(channel);\n }\n }, [onAddTopic]);\n\n const handleEditTopicClick = useCallback((channel: Channel) => {\n if (onEditTopic) {\n onEditTopic(channel);\n } else {\n setEditingTopicForChannel(channel);\n }\n }, [onEditTopic]);\n\n const handleToggleCloseTopicClick = useCallback(async (channel: Channel, isClosed: boolean) => {\n if (onToggleCloseTopic) {\n onToggleCloseTopic(channel, isClosed);\n return;\n }\n\n const parentCid = channel.data?.parent_cid as string | undefined;\n if (!parentCid) return;\n\n const parentChannel = client.activeChannels[parentCid];\n if (!parentChannel) return;\n\n try {\n if (isClosed) {\n await parentChannel.reopenTopic(channel.cid);\n } else {\n await parentChannel.closeTopic(channel.cid);\n }\n } catch (err) {\n console.error('Failed to toggle topic close state', err);\n }\n }, [client.activeChannels, onToggleCloseTopic]);\n\n // Group channels into pending and regular\n const { pendingChannels, regularChannels } = useMemo<{ pendingChannels: Channel[], regularChannels: Channel[] }>(() => {\n const pending: Channel[] = [];\n const pinned: Channel[] = [];\n const regular: Channel[] = [];\n\n channels.forEach(ch => {\n const ms = ch.state?.membership as Record<string, unknown> | undefined;\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n\n if (isSkipped) {\n return; // Filter out completely\n }\n\n if (isPending) {\n pending.push(ch);\n } else if (ch.data?.is_pinned) {\n pinned.push(ch);\n } else {\n regular.push(ch);\n }\n });\n\n return { pendingChannels: pending, regularChannels: [...pinned, ...regular] };\n }, [channels]);\n\n const filtersKey = useMemo(() => JSON.stringify(filters), [filters]);\n\n const loadChannels = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n const result = await client.queryChannels(filters, sort, options as { message_limit?: number });\n setChannels(result);\n } catch (err) {\n console.error('Failed to load channels:', err);\n setError(err);\n } finally {\n setLoading(false);\n }\n }, [client, filtersKey]);\n\n useEffect(() => {\n loadChannels();\n }, [loadChannels]);\n\n // Real-time: List manipulation (move to top, add, delete)\n useChannelListUpdates(channels, setChannels, scrollToTopOnOwnMessage ? handleOwnMessageNew : undefined);\n\n // Online status: compute set of online friend user IDs (skip if disabled)\n const onlineUsers = useOnlineUsers(showOnlineStatus ? channels : []);\n\n // Helper: get the \"other\" user ID from a direct channel\n const getOtherUserId = useCallback((channel: Channel): string | undefined => {\n if (!isDirectChannel(channel) || !client.userID) return undefined;\n const members = channel.state?.members;\n if (!members) return undefined;\n for (const memberId of Object.keys(members)) {\n if (memberId !== client.userID) return memberId;\n }\n return undefined;\n }, [client.userID]);\n\n // Helper: compute isOnline for a channel (undefined for non-friend channels)\n const getIsOnline = useCallback((channel: Channel): boolean | undefined => {\n const otherUserId = getOtherUserId(channel);\n if (!otherUserId || !client.userID) return undefined;\n if (!isFriendChannel(channel, otherUserId, client.userID)) return undefined;\n return onlineUsers.has(otherUserId);\n }, [getOtherUserId, onlineUsers, client.userID]);\n\n const handleSelect = useCallback(\n (channel: Channel) => {\n setActiveChannel(channel);\n onChannelSelect?.(channel);\n\n // Mark as read when user selects a channel (skip if banned, blocked, or pending)\n const activeCh = client.activeChannels[channel.cid] || channel;\n const ms = activeCh.state?.membership as Record<string, unknown> | undefined;\n const chState = activeCh.state as unknown as Record<string, unknown> | undefined;\n const isBannedInChannel = Boolean(ms?.banned);\n const isBlockedInChannel = isDirectChannel(activeCh) && Boolean(ms?.blocked);\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n\n if (!isBannedInChannel && !isBlockedInChannel && !isPending && !isSkipped) {\n let shouldUpdate = false;\n if ((chState?.unreadCount as number) > 0) {\n activeCh.markRead().catch(() => { });\n // Optimistically reset unread to update UI immediately\n if (chState) chState.unreadCount = 0;\n shouldUpdate = true;\n }\n \n // Also optimistic update on the stale channel just in case\n if (channel.state && (channel.state as any).unreadCount > 0) {\n (channel.state as any).unreadCount = 0;\n shouldUpdate = true;\n }\n\n if (shouldUpdate) {\n setChannels((prev) => [...prev]);\n }\n }\n },\n [setActiveChannel, onChannelSelect, setChannels],\n );\n\n if (loading) return <LoadingIndicator text={loadingLabel} />;\n if (error) return <ActualErrorIndicator text={errorLabel} onRetry={loadChannels} />;\n\n const isEmpty = showPendingInvites\n ? (pendingChannels.length === 0 && regularChannels.length === 0)\n : (regularChannels.length === 0);\n\n if (isEmpty) return <EmptyStateIndicator text={emptyStateLabel} />;\n\n return (\n <div className={`ermis-channel-list${className ? ` ${className}` : ''}`}>\n {/* VList requires its container to have a height to work. */}\n <VList ref={vlistRef} style={{ height: '100%' }}>\n {showPendingInvites && pendingChannels.length > 0 && (\n <div\n className=\"ermis-channel-list__accordion-header\"\n onClick={() => setIsPendingExpanded(prev => !prev)}\n >\n <span>\n {typeof pendingInvitesLabel === 'function'\n ? pendingInvitesLabel(pendingChannels.length)\n : pendingInvitesLabel || `Invites (${pendingChannels.length})`}\n </span>\n <svg\n className={`ermis-channel-list__accordion-icon ${isPendingExpanded ? 'ermis-channel-list__accordion-icon--expanded' : ''}`}\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n )}\n {showPendingInvites && isPendingExpanded && pendingChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onTruncateChannel={onTruncateChannel}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={getIsOnline(channel)}\n deletedMessageLabel={deletedMessageLabel}\n stickerMessageLabel={stickerMessageLabel}\n photoMessageLabel={photoMessageLabel}\n videoMessageLabel={videoMessageLabel}\n voiceRecordingMessageLabel={voiceRecordingMessageLabel}\n fileMessageLabel={fileMessageLabel}\n encryptedMessageLabel={encryptedMessageLabel}\n encryptedMessageUnavailableLabel={encryptedMessageUnavailableLabel}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n />\n );\n })}\n {/* {pendingChannels.length > 0 && regularChannels.length > 0 && (\n <div className=\"ermis-channel-list__accordion-header ermis-channel-list__accordion-header--static\">\n <span>{channelsLabel}</span>\n </div>\n )} */}\n {regularChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid ||\n (activeChannel?.data?.parent_cid === channel.cid);\n const isTeamWithTopics = hasTopicsEnabled(channel);\n\n if (isTeamWithTopics) {\n // Drill-down mode: always render flat item with topic pills + last msg\n const FlatComponent = FlatTopicGroupItemComponent || FlatTopicGroupItem;\n return (\n <FlatComponent\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n onDrillDown={(c) => {\n handleSelect(c);\n if (onTopicDrillDown) onTopicDrillDown(c);\n }}\n AvatarComponent={AvatarComponent}\n maxVisibleTopics={maxVisibleTopics}\n moreTopicsLabel={moreTopicsLabel}\n generalTopicLabel={generalTopicLabel}\n TopicPillComponent={TopicPillComponent}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={handleAddTopicClick}\n onTruncateChannel={onTruncateChannel}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n deletedMessageLabel={deletedMessageLabel}\n stickerMessageLabel={stickerMessageLabel}\n photoMessageLabel={photoMessageLabel}\n videoMessageLabel={videoMessageLabel}\n voiceRecordingMessageLabel={voiceRecordingMessageLabel}\n fileMessageLabel={fileMessageLabel}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n showTopicPills={showTopicPills}\n />\n );\n }\n\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={handleAddTopicClick}\n onEditTopic={handleEditTopicClick}\n onToggleCloseTopic={handleToggleCloseTopicClick}\n onDeleteTopic={onDeleteTopic}\n onTruncateChannel={onTruncateChannel}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={getIsOnline(channel)}\n deletedMessageLabel={deletedMessageLabel}\n stickerMessageLabel={stickerMessageLabel}\n photoMessageLabel={photoMessageLabel}\n videoMessageLabel={videoMessageLabel}\n voiceRecordingMessageLabel={voiceRecordingMessageLabel}\n fileMessageLabel={fileMessageLabel}\n encryptedMessageLabel={encryptedMessageLabel}\n encryptedMessageUnavailableLabel={encryptedMessageUnavailableLabel}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n />\n );\n })}\n </VList>\n {addingTopicForChannel && (\n <TopicModal\n isOpen={true}\n onClose={() => setAddingTopicForChannel(null)}\n parentChannel={addingTopicForChannel}\n EmojiPickerComponent={TopicEmojiPickerComponent}\n />\n )}\n {editingTopicForChannel && (\n <TopicModal\n isOpen={true}\n onClose={() => setEditingTopicForChannel(null)}\n topic={editingTopicForChannel}\n EmojiPickerComponent={TopicEmojiPickerComponent}\n />\n )}\n </div>\n );\n});\n\nChannelList.displayName = 'ChannelList';\n","import React, { useState, useCallback } from 'react';\nimport type { CreateTopicData, EditTopicData } from '@ermis-network/ermis-chat-sdk';\nimport { Modal as DefaultModal } from './Modal';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport type { TopicModalProps } from '../types';\n\nconst DEFAULT_TOPIC_ICONS = ['💬', '🔥', '🚀', '⭐', '💡', '🎉', '📌', '📁', '🎨', '💻', '📈', '🤝'];\n\nexport const TopicModal: React.FC<TopicModalProps> = React.memo(({\n isOpen,\n onClose,\n onSuccess,\n EmojiPickerComponent,\n parentChannel,\n topic,\n title = topic ? 'Edit Topic' : 'Create Topic',\n nameLabel = 'Topic Name',\n namePlaceholder = 'Enter topic name',\n emojiLabel = 'Topic icon',\n descriptionLabel = 'Description',\n descriptionPlaceholder = 'Enter topic description',\n cancelButtonLabel = 'Cancel',\n saveButtonLabel = topic ? 'Save' : 'Create',\n savingButtonLabel = topic ? 'Saving...' : 'Creating...',\n}) => {\n const { activeChannel, client } = useChatClient();\n const { ModalComponent } = useChatComponents();\n const Modal = ModalComponent || DefaultModal;\n \n const originalName = (topic?.data?.name as string) || '';\n const originalImage = (topic?.data?.image as string) || '';\n const originalEmoji = originalImage.startsWith('emoji://') ? originalImage.replace('emoji://', '') : '';\n const originalDescription = (topic?.data?.description as string) || '';\n\n const [name, setName] = useState(originalName);\n const [emoji, setEmoji] = useState(originalEmoji);\n const [description, setDescription] = useState(originalDescription);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const targetParent = parentChannel || activeChannel;\n\n const handleSave = useCallback(async () => {\n if (!name.trim() || !emoji) return;\n\n // Resolve parent channel (owner of topics)\n let editorParent = targetParent;\n if (topic && topic.data?.parent_cid) {\n editorParent = client.activeChannels[topic.data.parent_cid as string] || editorParent;\n }\n \n if (!editorParent && !topic) return;\n\n setIsSaving(true);\n setError(null);\n\n try {\n if (topic) {\n if (!editorParent) throw new Error(\"Parent channel not found\");\n \n const payload: EditTopicData = {};\n if (name.trim() !== originalName) payload.name = name.trim();\n if (emoji !== originalEmoji) payload.image = emoji ? `emoji://${emoji}` : '';\n if (description.trim() !== originalDescription) payload.description = description.trim();\n\n if (Object.keys(payload).length > 0 && topic.cid) {\n await editorParent.editTopic(topic.cid, payload);\n }\n\n if (onSuccess) {\n onSuccess(topic);\n } else {\n onClose();\n }\n } else {\n if (!editorParent) return;\n const payload: CreateTopicData = {\n name: name.trim(),\n };\n\n if (emoji) {\n payload.image = `emoji://${emoji}`;\n }\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n await editorParent.createTopic(payload);\n\n if (onSuccess) {\n onSuccess(editorParent);\n } else {\n onClose();\n setName('');\n setEmoji('');\n setDescription('');\n }\n }\n } catch (err: any) {\n setError(err?.message || (topic ? 'Failed to save topic' : 'Failed to create topic'));\n } finally {\n setIsSaving(false);\n }\n }, [targetParent, topic, name, emoji, description, originalName, originalEmoji, originalDescription, onSuccess, onClose, client.activeChannels]);\n\n const isValid = name.trim().length > 0 && emoji.length > 0;\n\n const footer = (\n <div className=\"ermis-create-topic__footer\">\n <button className=\"ermis-create-topic__btn ermis-create-topic__btn--cancel\" onClick={onClose} disabled={isSaving}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-topic__btn ermis-create-topic__btn--create\" onClick={handleSave} disabled={isSaving || !isValid}>\n {isSaving ? savingButtonLabel : saveButtonLabel}\n </button>\n </div>\n );\n\n return (\n <Modal isOpen={isOpen} onClose={isSaving ? () => { } : onClose} title={title} maxWidth=\"400px\" footer={footer}>\n <div className=\"ermis-create-topic__body\">\n <div className=\"ermis-create-topic__live-preview\">\n <span className=\"ermis-create-topic__live-preview-emoji\">{emoji || <span style={{opacity: 0.3}}>#</span>}</span>\n <span className=\"ermis-create-topic__live-preview-name\">{name || namePlaceholder}</span>\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{nameLabel} <span className=\"ermis-create-topic__required\">*</span></label>\n <input\n className=\"ermis-create-topic__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n autoFocus\n />\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{emojiLabel} <span className=\"ermis-create-topic__required\">*</span></label>\n\n <div className=\"ermis-create-topic__emoji-picker\">\n {EmojiPickerComponent ? (\n <EmojiPickerComponent onSelect={(e: any) => setEmoji(e.native || e.emoji || e.id || e)} />\n ) : (\n <div className=\"ermis-create-topic__default-icons\">\n {DEFAULT_TOPIC_ICONS.map(icon => (\n <button\n key={icon}\n type=\"button\"\n className={`ermis-create-topic__default-icon ${icon === emoji ? 'ermis-create-topic__default-icon--active' : ''}`}\n onClick={() => setEmoji(icon)}\n disabled={isSaving}\n >\n {icon}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-create-topic__input\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n style={{ resize: 'vertical' }}\n />\n </div>\n\n {error && (\n <div className=\"ermis-create-topic__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nTopicModal.displayName = 'TopicModal';\n","import React, { useState, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { ChannelAction, ChannelActionLabels, ChannelActionIcons, ChannelActionsProps } from '../types';\nimport { Dropdown } from './Dropdown';\nimport { isDirectChannel, isGroupChannel, isTopicChannel } from '../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../channelRoleUtils';\n\n/* ----------------------------------------------------------\n SVG Icons for default actions\n ---------------------------------------------------------- */\nconst PinIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /></svg>);\nconst UnpinIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /><line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\" /></svg>);\nconst BlockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" /></svg>);\nconst LeaveIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" /><polyline points=\"16 17 21 12 16 7\" /><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" /></svg>);\nconst TrashIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"3 6 5 6 21 6\" /><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" /></svg>);\nconst LockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 10 0v4\" /></svg>);\nconst UnlockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 9.9-1\" /></svg>);\nconst CreateTopicIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>);\nconst EditIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" /><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" /></svg>);\nconst MoreIcon = () => (<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"1\" /><circle cx=\"19\" cy=\"12\" r=\"1\" /><circle cx=\"5\" cy=\"12\" r=\"1\" /></svg>);\n\n/* ----------------------------------------------------------\n computeDefaultActions\n Derives a list of ChannelAction[] based on channel type\n and the current user's role. Currently actions only log\n to console — real API calls will be wired later.\n ---------------------------------------------------------- */\nexport function computeDefaultActions(\n channel: Channel,\n currentUserId?: string,\n options?: {\n onAddTopic?: (channel: Channel) => void;\n onEditTopic?: (channel: Channel) => void;\n onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;\n onDeleteTopic?: (channel: Channel) => void;\n onTruncateChannel?: (channel: Channel) => void;\n isBlocked?: boolean;\n actionLabels?: ChannelActionLabels;\n actionIcons?: ChannelActionIcons;\n },\n): ChannelAction[] {\n const actions: ChannelAction[] = [];\n if (!currentUserId) return actions;\n\n const isDirect = isDirectChannel(channel);\n const isTeamOrMeeting = isGroupChannel(channel);\n const isTopic = isTopicChannel(channel);\n const isClosed = channel.data?.is_closed_topic === true;\n\n const ms = channel.state?.members?.[currentUserId] || channel.state?.membership;\n const role = ms?.channel_role;\n const isBlocked = options?.isBlocked !== undefined ? options.isBlocked : (ms as any)?.blocked;\n const isPinned = channel.data?.is_pinned === true;\n\n // Pin / Unpin — available for all channel types\n const actionLabels = options?.actionLabels;\n\n const pinLabel = isPinned\n ? (isTopic ? (actionLabels?.unpinTopic || 'Unpin topic') : (actionLabels?.unpinChannel || 'Unpin channel'))\n : (isTopic ? (actionLabels?.pinTopic || 'Pin topic') : (actionLabels?.pinChannel || 'Pin channel'));\n\n const actionIcons = options?.actionIcons;\n\n const pinIcon = isPinned\n ? (actionIcons?.UnpinIcon || <UnpinIcon />)\n : (actionIcons?.PinIcon || <PinIcon />);\n\n actions.push({\n id: isPinned ? 'unpin' : 'pin',\n label: pinLabel,\n icon: pinIcon,\n onClick: async (ch) => {\n try {\n if (isPinned) {\n await ch.unpin();\n } else {\n await ch.pin();\n }\n } catch (e) {\n console.error('Error toggling pin state', e);\n }\n },\n });\n\n if (isDirect) {\n // Direct channel: Block / Unblock\n actions.push({\n id: isBlocked ? 'unblock' : 'block',\n label: isBlocked ? (actionLabels?.unblockUser || 'Unblock user') : (actionLabels?.blockUser || 'Block user'),\n icon: isBlocked ? (actionIcons?.UnblockIcon || <BlockIcon />) : (actionIcons?.BlockIcon || <BlockIcon />),\n isDanger: !isBlocked,\n onClick: async (ch) => {\n try {\n if (isBlocked) {\n await ch.unblockUser();\n } else {\n await ch.blockUser();\n }\n } catch (e) {\n console.error('Error toggling block state', e);\n }\n },\n });\n\n // Direct channel: Truncate / Clear history\n actions.push({\n id: 'truncate',\n label: actionLabels?.truncateChannel || 'Clear history',\n icon: actionIcons?.TruncateChannelIcon || <TrashIcon />,\n isDanger: true,\n onClick: async (ch) => {\n if (options?.onTruncateChannel) {\n await options.onTruncateChannel(ch);\n } else {\n try {\n await ch.truncate();\n } catch (e) {\n console.error('Error clearing channel history', e);\n }\n }\n },\n });\n } else if (isTopic) {\n // Topic: Edit topic (owner & moder only)\n if (canManageChannel(role)) {\n actions.push({\n id: 'edit_topic',\n label: actionLabels?.editTopic || 'Edit topic',\n icon: actionIcons?.EditTopicIcon || <EditIcon />,\n onClick: (ch) => {\n options?.onEditTopic?.(ch);\n },\n });\n }\n // Topic: Close / Reopen (owner & moder only)\n if (canManageChannel(role)) {\n actions.push({\n id: isClosed ? 'reopen' : 'close',\n label: isClosed ? (actionLabels?.reopenTopic || 'Reopen topic') : (actionLabels?.closeTopic || 'Close topic'),\n icon: isClosed ? (actionIcons?.ReopenTopicIcon || <UnlockIcon />) : (actionIcons?.CloseTopicIcon || <LockIcon />),\n isDanger: !isClosed,\n onClick: async (ch) => {\n if (options?.onToggleCloseTopic) {\n await options.onToggleCloseTopic(ch, isClosed);\n return;\n }\n // Default behavior: call SDK API directly\n const parentCid = ch.data?.parent_cid as string | undefined;\n if (!parentCid) return;\n try {\n const client = ch.getClient();\n const parentChannel = client.activeChannels[parentCid];\n if (!parentChannel) return;\n if (isClosed) {\n await parentChannel.reopenTopic(ch.cid);\n } else {\n await parentChannel.closeTopic(ch.cid);\n }\n } catch (err) {\n console.error('Failed to toggle topic close state', err);\n }\n },\n });\n }\n // Topic: Delete (owner only)\n if (role === CHANNEL_ROLES.OWNER) {\n actions.push({\n id: 'delete_topic',\n label: actionLabels?.deleteTopic || 'Delete topic',\n icon: actionIcons?.DeleteTopicIcon || <TrashIcon />,\n isDanger: true,\n onClick: async (ch) => {\n if (options?.onDeleteTopic) {\n await options.onDeleteTopic(ch);\n return;\n }\n try {\n await ch.delete();\n } catch (err) {\n console.error('Failed to delete topic', err);\n }\n },\n });\n }\n } else if (isTeamOrMeeting) {\n // Team channel: Create Topic (owner & moder, only if topics enabled)\n const hasTopicsEnabled = Boolean(channel.data?.topics_enabled);\n if (hasTopicsEnabled && canManageChannel(role) && options?.onAddTopic) {\n actions.push({\n id: 'create_topic',\n label: actionLabels?.createTopic || 'Create topic',\n icon: actionIcons?.CreateTopicIcon || <CreateTopicIcon />,\n onClick: (ch) => { options.onAddTopic!(ch); },\n });\n }\n if (role === CHANNEL_ROLES.OWNER) {\n actions.push({\n id: 'delete',\n label: actionLabels?.deleteChannel || 'Delete channel',\n icon: actionIcons?.DeleteChannelIcon || <TrashIcon />,\n isDanger: true,\n onClick: async (ch) => {\n try {\n await ch.delete();\n } catch (e) {\n console.error('Error deleting channel', e);\n }\n },\n });\n }\n if (role === CHANNEL_ROLES.MODERATOR || role === CHANNEL_ROLES.MEMBER) {\n actions.push({\n id: 'leave',\n label: actionLabels?.leaveChannel || 'Leave channel',\n icon: actionIcons?.LeaveChannelIcon || <LeaveIcon />,\n isDanger: true,\n onClick: async (ch) => {\n try {\n if (ch.data?.mls_enabled) {\n await ch.leaveChannelE2ee(currentUserId);\n } else {\n await ch.removeMembers([currentUserId]);\n }\n } catch (e) {\n console.error('Error leaving channel', e);\n throw e;\n }\n },\n });\n }\n }\n\n return actions;\n}\n\n/* ----------------------------------------------------------\n DefaultChannelActions\n The default UI component that renders the \"more\" trigger\n button and the dropdown menu. Consumer can fully replace\n this via ChannelActionsComponent prop.\n ---------------------------------------------------------- */\nexport const DefaultChannelActions: React.FC<ChannelActionsProps> = React.memo(({ channel, actions, onClose }) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n\n const handleActionsClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n setDropdownOpen(true);\n }, []);\n\n const handleClose = useCallback(() => {\n setDropdownOpen(false);\n setAnchorRect(null);\n onClose();\n }, [onClose]);\n\n if (!actions || actions.length === 0) return null;\n\n return (\n <>\n <button\n type=\"button\"\n className={`ermis-channel-list__actions-trigger ${dropdownOpen ? 'ermis-channel-list__actions-trigger--active' : ''}`}\n onClick={handleActionsClick}\n title=\"More actions\"\n >\n <MoreIcon />\n </button>\n <Dropdown\n isOpen={dropdownOpen}\n anchorRect={anchorRect}\n onClose={handleClose}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.map((action) => (\n <button\n key={action.id}\n className={`ermis-dropdown__item ${action.isDanger ? 'ermis-dropdown__item--danger' : ''}`}\n onClick={(e) => {\n e.stopPropagation();\n handleClose();\n action.onClick(channel, e);\n }}\n >\n {action.icon}\n <span>{action.label}</span>\n </button>\n ))}\n </div>\n </Dropdown>\n </>\n );\n});\n\nDefaultChannelActions.displayName = 'DefaultChannelActions';\n","import React, { useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\n\n// Global event name used to close any other open dropdowns\nconst CLOSE_ALL_EVENT = 'ermis:close-all-dropdowns';\n\n/** Dispatch a global event to close all open dropdowns */\nexport const closeAllDropdowns = () => {\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT));\n};\n\nimport type { DropdownProps } from '../types';\n\nexport const Dropdown: React.FC<DropdownProps> = ({\n isOpen,\n anchorRect,\n onClose,\n children,\n align = 'left',\n className = '',\n style: propStyle = {},\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceId = useRef(Math.random().toString(36).slice(2));\n\n // Listen for global close event — only register when open to avoid N listeners\n useEffect(() => {\n if (!isOpen) return;\n\n // Broadcast: close all OTHER open dropdowns\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT, { detail: instanceId.current }));\n\n const handleGlobalClose = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (!detail || detail !== instanceId.current) {\n onClose();\n }\n };\n\n const handleClickOutside = (e: MouseEvent) => {\n // Allow the click to process if it's on a trigger button so it can toggle itself\n // We rely on the trigger stopping propagation or using the global close event.\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n\n const handleScroll = () => onClose();\n\n // Delay click listener to prevent instant close from the opening click\n const tid = setTimeout(() => {\n document.addEventListener('click', handleClickOutside);\n }, 10);\n\n document.addEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n\n return () => {\n clearTimeout(tid);\n document.removeEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.removeEventListener('click', handleClickOutside);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n };\n }, [isOpen, onClose]);\n\n if (!isOpen || !anchorRect) return null;\n\n const spaceBelow = window.innerHeight - anchorRect.bottom;\n const spaceAbove = anchorRect.top;\n const estimatedDropdownHeight = 250;\n\n let verticalStyle: React.CSSProperties = {};\n if (spaceBelow < estimatedDropdownHeight && spaceAbove > spaceBelow) {\n // Open upwards (bottom-aligned to the top of the trigger)\n verticalStyle = { bottom: window.innerHeight - anchorRect.top + 4 };\n } else {\n // Open downwards\n verticalStyle = { top: anchorRect.bottom + 4 };\n }\n\n const style: React.CSSProperties = {\n position: 'fixed',\n zIndex: 99999,\n ...verticalStyle,\n ...(align === 'right'\n ? { right: window.innerWidth - anchorRect.right }\n : { left: anchorRect.left }),\n ...propStyle\n };\n\n const portalTarget = document.querySelector('.ermis-chat') || document.body;\n\n return createPortal(\n <div ref={containerRef} className={`ermis-dropdown ${className}`.trim()} style={style}>\n {children}\n </div>,\n portalTarget\n );\n};\n","import React, { useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { SystemMessageTranslations, SignalMessageTranslations } from '@ermis-network/ermis-chat-sdk';\nimport { useTopicGroupUpdates } from '../hooks/useTopicGroupUpdates';\nimport { useChannelRowUpdates } from '../hooks/useChannelRowUpdates';\nimport { DefaultChannelActions, computeDefaultActions } from './ChannelActions';\nimport type { AvatarProps, ChannelActionsProps, ChannelActionLabels, ChannelActionIcons, TopicPillProps } from '../types';\n\n/* ----------------------------------------------------------\n Default TopicPill – renders a single topic preview\n ---------------------------------------------------------- */\nconst DefaultTopicPill: React.FC<TopicPillProps> = React.memo(({ topic }) => {\n const image = topic.data?.image as string | undefined;\n\n let emoji = '💬';\n if (image && typeof image === 'string' && image.startsWith('emoji://')) {\n emoji = image.replace('emoji://', '');\n }\n\n const name = topic.data?.name || '';\n\n return (\n <span className=\"ermis-channel-list__topic-pill\">\n <span className=\"ermis-channel-list__topic-pill-avatar\">{emoji}</span>\n {name && <span className=\"ermis-channel-list__topic-pill-name\">{name}</span>}\n </span>\n );\n});\nDefaultTopicPill.displayName = 'DefaultTopicPill';\n\n/* ----------------------------------------------------------\n FlatTopicGroupItem Props\n ---------------------------------------------------------- */\ntype FlatTopicGroupItemProps = {\n channel: Channel;\n isActive: boolean;\n onDrillDown?: (channel: Channel) => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n maxVisibleTopics?: number;\n moreTopicsLabel?: string;\n /** Label for the general pill (default: 'general') */\n generalTopicLabel?: string;\n TopicPillComponent?: React.ComponentType<TopicPillProps>;\n PinnedIconComponent?: React.ComponentType;\n ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;\n onAddTopic?: (channel: Channel) => void;\n onTruncateChannel?: (channel: Channel) => void;\n hiddenActions?: string[];\n actionLabels?: ChannelActionLabels;\n actionIcons?: ChannelActionIcons;\n deletedMessageLabel?: React.ReactNode;\n stickerMessageLabel?: React.ReactNode;\n photoMessageLabel?: React.ReactNode;\n videoMessageLabel?: React.ReactNode;\n voiceRecordingMessageLabel?: React.ReactNode;\n fileMessageLabel?: React.ReactNode;\n systemMessageTranslations?: SystemMessageTranslations;\n signalMessageTranslations?: SignalMessageTranslations;\n showTopicPills?: boolean;\n};\n\n/* ----------------------------------------------------------\n FlatTopicGroupItem – flat channel item with topic preview\n Shows like a normal ChannelItem (name, last msg, timestamp,\n unread badge) plus a row of topic pills.\n ---------------------------------------------------------- */\nexport const FlatTopicGroupItem: React.FC<FlatTopicGroupItemProps> = React.memo(({\n channel,\n isActive,\n onDrillDown,\n AvatarComponent,\n maxVisibleTopics = 3,\n moreTopicsLabel = '...',\n generalTopicLabel = 'general',\n TopicPillComponent,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n showTopicPills = false,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Realtime updates for parent channel row (pin/unpin, channel.updated)\n const { updateCount } = useChannelRowUpdates(channel, currentUserId);\n\n // Realtime topic group data (sorted topics, aggregated unread, latest message)\n const { topics, aggregatedUnreadCount, hasUnread, latestMessagePreview } = useTopicGroupUpdates(\n channel,\n currentUserId,\n {\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n }\n );\n\n const name = channel.data?.name || channel.cid;\n const image = channel.data?.image as string | undefined;\n const isPinned = channel.data?.is_pinned === true;\n // For topic groups, always show the unread badge if there are unreads.\n // Unlike normal channels, isActive only means the user is viewing ONE topic,\n // not that they've read ALL topics. The aggregatedUnreadCount already correctly\n // reflects only the truly unread topics.\n const showUnread = hasUnread;\n\n // Latest message data from the aggregated preview\n const lastMessageText = latestMessagePreview?.text || '';\n const lastMessageUser = latestMessagePreview?.user || '';\n const lastMessageTimestamp = latestMessagePreview?.timestamp;\n const lastMessageSourceName = latestMessagePreview?.sourceName || null;\n\n const timestampText = useMemo(() => {\n if (!lastMessageTimestamp) return null;\n const d = new Date(lastMessageTimestamp);\n if (isNaN(d.getTime())) return null;\n const today = new Date();\n const isToday = d.toDateString() === today.toDateString();\n return isToday\n ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n : d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }, [lastMessageTimestamp]);\n\n // Visible topic pills: general pill + sub-topic pills (capped at maxVisibleTopics)\n const visibleTopics = useMemo(\n () => topics.slice(0, Math.max(0, maxVisibleTopics - 1)),\n [topics, maxVisibleTopics],\n );\n const hasOverflow = (topics.length + 1) > maxVisibleTopics; // +1 for general pill\n\n // Actions menu (pin, create topic, delete, leave)\n const defaultActions = useMemo(\n () => computeDefaultActions(channel, currentUserId, { onAddTopic, actionLabels, actionIcons }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [channel, currentUserId, updateCount, onAddTopic, actionLabels, actionIcons],\n );\n const filteredActions = useMemo(() => {\n if (!hiddenActions || hiddenActions.length === 0) return defaultActions;\n return defaultActions.filter((a) => !hiddenActions.includes(a.id));\n }, [defaultActions, hiddenActions]);\n const ActionsComponent = ChannelActionsComponent || DefaultChannelActions;\n\n const Pill = TopicPillComponent || DefaultTopicPill;\n\n const handleClick = useCallback(() => {\n if (onDrillDown) onDrillDown(channel);\n }, [channel, onDrillDown]);\n\n const itemClass = [\n 'ermis-channel-list__item',\n 'ermis-channel-list__item--topic-group',\n isActive ? 'ermis-channel-list__item--active' : '',\n showUnread ? 'ermis-channel-list__item--unread' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} onClick={handleClick}>\n <div className=\"ermis-channel-list__item-avatar-wrapper\">\n <AvatarComponent image={image} name={name} size={45} disableLightbox className=\"ermis-avatar-wrapper--group\" />\n {showUnread && aggregatedUnreadCount > 0 && (\n <span className=\"ermis-channel-list__avatar-unread-badge\">\n {aggregatedUnreadCount > 99 ? '99+' : aggregatedUnreadCount}\n </span>\n )}\n </div>\n <div className=\"ermis-channel-list__item-content\">\n {/* Row 1: name + pinned + timestamp */}\n <div className=\"ermis-channel-list__item-top-row\">\n <div className=\"ermis-channel-list__item-name\">{name}</div>\n {isPinned && PinnedIconComponent && (\n <span className=\"ermis-channel-list__pinned-icon\" title=\"Pinned\">\n <PinnedIconComponent />\n </span>\n )}\n {timestampText && <div className=\"ermis-channel-list__item-timestamp\">{timestampText}</div>}\n </div>\n {/* Row 2: last message + unread badge */}\n <div className=\"ermis-channel-list__item-bottom-row\">\n {lastMessageText && (\n <div className=\"ermis-channel-list__item-last-message\">\n {lastMessageSourceName && (\n <span className=\"ermis-channel-list__item-last-message-source\">\n #{lastMessageSourceName} · {' '}\n </span>\n )}\n {lastMessageUser && (\n <span className=\"ermis-channel-list__item-last-message-user\">\n {lastMessageUser}:{' '}\n </span>\n )}\n <span>{lastMessageText}</span>\n </div>\n )}\n <div className=\"ermis-channel-list__item-badges\">\n {showUnread && aggregatedUnreadCount > 0 && (\n <span className=\"ermis-channel-list__unread-badge\">\n {aggregatedUnreadCount > 99 ? '99+' : aggregatedUnreadCount}\n </span>\n )}\n </div>\n </div>\n {/* Row 3: topic pills — always visible (at least general pill) */}\n <div className=\"ermis-channel-list__item-topics-row\">\n {showTopicPills && (\n <div className=\"ermis-channel-list__topic-pills\">\n <span className=\"ermis-channel-list__topic-pill\">\n <span className=\"ermis-channel-list__topic-pill-avatar\">#</span>\n <span className=\"ermis-channel-list__topic-pill-name\">{generalTopicLabel}</span>\n </span>\n {visibleTopics.map((topic: Channel) => (\n <Pill key={topic.cid} topic={topic} />\n ))}\n {hasOverflow && (\n <span className=\"ermis-channel-list__topic-overflow\">{moreTopicsLabel}</span>\n )}\n </div>\n )}\n </div>\n </div>\n <div className=\"ermis-channel-list__item-actions-wrapper\">\n <ActionsComponent channel={channel} actions={filteredActions} onClose={() => { }} />\n </div>\n </div>\n );\n});\nFlatTopicGroupItem.displayName = 'FlatTopicGroupItem';\n","import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport { VList as _VList, type VListHandle } from 'virtua';\nconst VList = _VList as any;\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useTopicGroupUpdates } from '../hooks/useTopicGroupUpdates';\nimport { ChannelRow } from './ChannelList';\nimport { ChannelItem } from './ChannelList';\nimport { Avatar } from './Avatar';\nimport { DefaultPinnedIcon } from './ChannelList';\nimport { TopicModal } from './TopicModal';\nimport { isPendingMember, isSkippedMember } from '../channelRoleUtils';\nimport type { TopicListProps } from '../types';\n\n/* ----------------------------------------------------------\n Default avatars for general and topic items\n ---------------------------------------------------------- */\nconst DefaultGeneralAvatar = React.memo(() => (\n <div className=\"ermis-channel-list__topic-hashtag\">#</div>\n));\nDefaultGeneralAvatar.displayName = 'DefaultGeneralAvatar';\n\nconst DefaultTopicEmojiAvatar = React.memo(({ image }: { image?: string | null }) => {\n let emoji = '💬';\n if (image && typeof image === 'string' && image.startsWith('emoji://')) {\n emoji = image.replace('emoji://', '');\n }\n return <div className=\"ermis-channel-list__topic-hashtag\">{emoji}</div>;\n});\nDefaultTopicEmojiAvatar.displayName = 'DefaultTopicEmojiAvatar';\n\n/* ----------------------------------------------------------\n TopicList – headless virtualized list of topics\n ---------------------------------------------------------- */\nexport const TopicList: React.FC<TopicListProps> = React.memo(({\n channel,\n ChannelItemComponent = ChannelItem,\n AvatarComponent = Avatar,\n GeneralAvatarComponent,\n TopicAvatarComponent,\n generalTopicLabel = 'general',\n PinnedIconComponent = DefaultPinnedIcon,\n ChannelActionsComponent,\n onSelectTopic,\n onEditTopic,\n onToggleCloseTopic,\n onDeleteTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n closedTopicIcon,\n pendingBadgeLabel,\n blockedBadgeLabel,\n scrollToTopOnOwnMessage = true,\n deletedMessageLabel,\n stickerMessageLabel,\n photoMessageLabel,\n videoMessageLabel,\n voiceRecordingMessageLabel,\n fileMessageLabel,\n encryptedMessageLabel,\n encryptedMessageUnavailableLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n}) => {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n const currentUserId = client.userID;\n const { topics } = useTopicGroupUpdates(channel, currentUserId);\n\n // Ref for imperative scroll control on the virtualized list\n const vlistRef = useRef<VListHandle>(null);\n\n // Auto-scroll to top when the current user sends a message in any topic\n useEffect(() => {\n if (!scrollToTopOnOwnMessage || !currentUserId) return;\n\n const subs: { unsubscribe: () => void }[] = [];\n\n const handleNewMessage = (event: { user?: { id?: string } }) => {\n if (event.user?.id === currentUserId) {\n setTimeout(() => vlistRef.current?.scrollToIndex(0), 0);\n }\n };\n\n // Listen on parent channel\n subs.push(channel.on('message.new', handleNewMessage));\n\n // Listen on all sub-topics\n const currentTopics = channel.state?.topics || [];\n currentTopics.forEach((t: Channel) => {\n subs.push(t.on('message.new', handleNewMessage));\n });\n\n return () => {\n subs.forEach((s) => s.unsubscribe());\n };\n }, [channel, channel.state?.topics, currentUserId, scrollToTopOnOwnMessage]);\n\n // Default edit topic handler: open built-in TopicModal when no custom handler is provided\n const [editingTopic, setEditingTopic] = useState<Channel | null>(null);\n\n const handleEditTopic = useCallback((topic: Channel) => {\n if (onEditTopic) {\n onEditTopic(topic);\n } else {\n setEditingTopic(topic);\n }\n }, [onEditTopic]);\n\n // General channel proxy — display parent channel as the general topic\n const generalProxy = useMemo(() => {\n return new Proxy(channel, {\n get(target, prop, receiver) {\n if (prop === 'data') {\n return { ...target.data, name: generalTopicLabel, is_pinned: false };\n }\n const value = Reflect.get(target, prop, receiver);\n return typeof value === 'function' ? value.bind(target) : value;\n }\n });\n }, [channel, generalTopicLabel]);\n\n const markChannelRead = useCallback((ch: Channel) => {\n const client = ch.getClient();\n const activeCh = client.activeChannels[ch.cid] || ch;\n const ms = activeCh.state?.membership as Record<string, unknown> | undefined;\n const chState = activeCh.state as unknown as Record<string, unknown> | undefined;\n const isBannedInChannel = Boolean(ms?.banned);\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n\n if (!isBannedInChannel && !isPending && !isSkipped) {\n if ((chState?.unreadCount as number) > 0) {\n activeCh.markRead().catch(() => { });\n if (chState) chState.unreadCount = 0;\n }\n \n // Always clear the stale channel just in case to fix UI ghost badges\n if (ch.state && (ch.state as any).unreadCount > 0) {\n (ch.state as any).unreadCount = 0;\n }\n }\n }, []);\n\n const handleSelectGeneral = useCallback(() => {\n if (onSelectTopic) {\n onSelectTopic(channel);\n } else {\n setActiveChannel(channel);\n }\n markChannelRead(channel);\n }, [channel, onSelectTopic, setActiveChannel, markChannelRead]);\n\n const handleSelectTopic = useCallback((topic: Channel) => {\n if (onSelectTopic) {\n onSelectTopic(topic);\n } else {\n setActiveChannel(topic);\n }\n markChannelRead(topic);\n }, [onSelectTopic, setActiveChannel, markChannelRead]);\n\n /** Null actions component for the general item */\n const NoActions = useCallback(() => null, []);\n\n return (\n <>\n <VList ref={vlistRef} style={{ height: '100%' }}>\n {/* General (parent channel) — no actions menu */}\n <ChannelRow\n channel={generalProxy as Channel}\n isActive={activeChannel?.cid === channel.cid}\n handleSelect={handleSelectGeneral}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={GeneralAvatarComponent || DefaultGeneralAvatar as any}\n currentUserId={currentUserId}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n ChannelActionsComponent={NoActions}\n hiddenActions={hiddenActions}\n deletedMessageLabel={deletedMessageLabel}\n stickerMessageLabel={stickerMessageLabel}\n photoMessageLabel={photoMessageLabel}\n videoMessageLabel={videoMessageLabel}\n voiceRecordingMessageLabel={voiceRecordingMessageLabel}\n fileMessageLabel={fileMessageLabel}\n encryptedMessageLabel={encryptedMessageLabel}\n encryptedMessageUnavailableLabel={encryptedMessageUnavailableLabel}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n />\n {/* Sub-topics — with full data (last msg, unread, timestamp, pin icon) */}\n {topics.map((topic: Channel) => (\n <ChannelRow\n key={topic.cid}\n channel={topic}\n isActive={activeChannel?.cid === topic.cid}\n handleSelect={handleSelectTopic}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={TopicAvatarComponent || DefaultTopicEmojiAvatar as any}\n currentUserId={currentUserId}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onEditTopic={handleEditTopic}\n onToggleCloseTopic={onToggleCloseTopic}\n onDeleteTopic={onDeleteTopic}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n deletedMessageLabel={deletedMessageLabel}\n stickerMessageLabel={stickerMessageLabel}\n photoMessageLabel={photoMessageLabel}\n videoMessageLabel={videoMessageLabel}\n voiceRecordingMessageLabel={voiceRecordingMessageLabel}\n fileMessageLabel={fileMessageLabel}\n encryptedMessageLabel={encryptedMessageLabel}\n encryptedMessageUnavailableLabel={encryptedMessageUnavailableLabel}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n />\n ))}\n </VList>\n {editingTopic && (\n <TopicModal\n isOpen={true}\n onClose={() => setEditingTopic(null)}\n topic={editingTopic}\n />\n )}\n </>\n );\n});\nTopicList.displayName = 'TopicList';\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { ForwardMessageModal } from './ForwardMessageModal';\nimport type { ChannelProps } from '../types';\n\nexport type { ChannelProps } from '../types';\n\nconst DefaultEmpty = React.memo(() => (\n <div className=\"ermis-channel__empty\">Select a channel to start chatting</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/**\n * Channel wrapper component.\n *\n * Customization:\n * - `HeaderComponent` — replace default ChannelHeader with a fully custom component.\n * Receives `{ channel, name, image }` as props.\n * - `EmptyStateIndicator` — custom component when no channel is selected.\n */\nexport const Channel: React.FC<ChannelProps> = React.memo(({\n children,\n className,\n EmptyStateIndicator = DefaultEmpty,\n HeaderComponent,\n ForwardMessageModalComponent: ForwardMessageModalProp,\n}) => {\n const { activeChannel, client, forwardingMessage, setForwardingMessage } = useChatClient();\n const { ForwardMessageModalComponent: ForwardMessageModalContext } = useChatComponents();\n\n const ForwardMessageModalView = ForwardMessageModalProp || ForwardMessageModalContext || ForwardMessageModal;\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n\n // Force re-render when channel info is updated via WS\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n useEffect(() => {\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount((c) => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const headerData = useMemo(() => {\n if (!activeChannel || !HeaderComponent) return null;\n return {\n channel: activeChannel,\n name: (activeChannel.data?.name || activeChannel.cid || '') as string,\n image: activeChannel.data?.image as string | undefined,\n };\n }, [activeChannel, HeaderComponent, channelUpdateCount]);\n\n if (!activeChannel) {\n return <EmptyStateIndicator />;\n }\n\n const bannedClass = isBanned ? ' ermis-channel--banned' : '';\n const blockedClass = isBlocked ? ' ermis-channel--blocked' : '';\n\n return (\n <div className={`ermis-channel${bannedClass}${blockedClass}${className ? ` ${className}` : ''}`}>\n {HeaderComponent && headerData && <HeaderComponent {...headerData} />}\n {children}\n {forwardingMessage && (\n <ForwardMessageModalView\n message={forwardingMessage}\n onDismiss={() => setForwardingMessage(null)}\n />\n )}\n </div>\n );\n});\n\nChannel.displayName = 'Channel';\n\n","import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { Modal as DefaultModal } from './Modal';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport type { ForwardMessageModalProps, ForwardChannelItemProps } from '../types';\nimport { isTopicChannel } from '../channelTypeUtils';\nimport { useForwardMessage } from '../hooks/useForwardMessage';\n\nexport type { ForwardMessageModalProps, ForwardChannelItemProps } from '../types';\n\n/* ----------------------------------------------------------\n Default channel item row with checkbox\n ---------------------------------------------------------- */\nconst DefaultForwardChannelItem: React.FC<ForwardChannelItemProps> = React.memo(({\n channel,\n selected,\n onToggle,\n AvatarComponent,\n}) => {\n const { client } = useChatClient();\n const isTopic = isTopicChannel(channel);\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parent = parentCid ? client.activeChannels[parentCid] : null;\n const parentName = parent?.data?.name || '';\n\n const name = (channel.data?.name || channel.cid) as string;\n const rawImage = channel.data?.image as string | undefined;\n // Parse emoji:// format → extract just the emoji for avatar fallback\n const isEmoji = rawImage?.startsWith('emoji://');\n const image = isEmoji ? undefined : rawImage;\n\n // Use # for topics without explicit emoji/image\n const emojiIcon = isEmoji ? rawImage!.replace('emoji://', '') : (isTopic && !image ? '#' : undefined);\n\n return (\n <div\n className={`ermis-forward-modal__channel-item ${selected ? 'ermis-forward-modal__channel-item--selected' : ''}`}\n onClick={() => onToggle(channel)}\n >\n {emojiIcon ? (\n <span className=\"ermis-forward-modal__channel-emoji\" style={{ fontSize: 24, width: 36, textAlign: 'center' }}>{emojiIcon}</span>\n ) : (\n <AvatarComponent image={image} name={name} size={36} />\n )}\n <div className=\"ermis-forward-modal__channel-name-container\">\n {isTopic && parentName && (\n <span className=\"ermis-forward-modal__channel-parent-name\">{parentName}</span>\n )}\n <span className=\"ermis-forward-modal__channel-name\">{name}</span>\n </div>\n <div className={`ermis-forward-modal__checkbox ${selected ? 'ermis-forward-modal__checkbox--checked' : ''}`}>\n {selected && (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n </div>\n </div>\n );\n});\nDefaultForwardChannelItem.displayName = 'DefaultForwardChannelItem';\n\n/* ----------------------------------------------------------\n ForwardMessageModal\n ---------------------------------------------------------- */\nexport const ForwardMessageModal: React.FC<ForwardMessageModalProps> = ({\n message,\n onDismiss,\n ChannelItemComponent = DefaultForwardChannelItem,\n SearchInputComponent,\n}) => {\n const { ModalComponent } = useChatComponents();\n const Modal = ModalComponent || DefaultModal;\n const backdropRef = useRef<HTMLDivElement>(null);\n const { client } = useChatClient();\n\n const {\n search,\n setSearch,\n selectedChannels,\n toggleChannel,\n sending,\n results,\n filteredChannels,\n handleSend,\n } = useForwardMessage(message, onDismiss);\n\n /* ---------- Keyboard / backdrop close ---------- */\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onDismiss();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [onDismiss]);\n\n const handleBackdropClick = useCallback((e: React.MouseEvent) => {\n if (e.target === backdropRef.current) onDismiss();\n }, [onDismiss]);\n\n /* ---------- Message preview ---------- */\n let previewText = message.text || '';\n \n if (previewText && message.mentioned_users && message.mentioned_users.length > 0) {\n message.mentioned_users.forEach((userId) => {\n const name = client.state.users[userId]?.name || userId;\n previewText = previewText.replace(new RegExp(`@${userId}`, 'g'), `@${name}`);\n });\n }\n\n previewText = previewText.length > 120 ? previewText.slice(0, 120) + '…' : previewText;\n const attachmentCount = message.attachments?.length ?? 0;\n\n const footer = (\n <>\n <button className=\"ermis-forward-modal__btn ermis-forward-modal__btn--cancel\" onClick={onDismiss}>\n Cancel\n </button>\n <button\n className=\"ermis-forward-modal__btn ermis-forward-modal__btn--send\"\n onClick={handleSend}\n disabled={selectedChannels.size === 0 || sending || results !== null}\n >\n {sending ? 'Sending…' : `Forward${selectedChannels.size > 0 ? ` (${selectedChannels.size})` : ''}`}\n </button>\n </>\n );\n\n return (\n <Modal isOpen onClose={onDismiss} title=\"Forward Message\" footer={footer}>\n {/* Message preview */}\n <div className=\"ermis-forward-modal__preview\">\n <div className=\"ermis-forward-modal__preview-sender\">\n {message.user?.name || message.user_id || 'Unknown'}\n </div>\n {previewText && (\n <div className=\"ermis-forward-modal__preview-text\">{previewText}</div>\n )}\n {attachmentCount > 0 && (\n <div className=\"ermis-forward-modal__preview-attachments\">\n 📎 {attachmentCount} attachment{attachmentCount > 1 ? 's' : ''}\n </div>\n )}\n </div>\n\n {/* Search */}\n <div className=\"ermis-forward-modal__search-wrapper\">\n {SearchInputComponent ? (\n <SearchInputComponent value={search} onChange={setSearch} />\n ) : (\n <input\n className=\"ermis-forward-modal__search\"\n type=\"text\"\n placeholder=\"Search channels…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n autoFocus\n />\n )}\n </div>\n\n {/* Channel list */}\n <div className=\"ermis-forward-modal__channel-list\">\n {filteredChannels.length === 0 ? (\n <div className=\"ermis-forward-modal__empty\">No channels found</div>\n ) : (\n filteredChannels.map((ch) => (\n <ChannelItemComponent\n key={ch.cid}\n channel={ch}\n selected={selectedChannels.has(ch.cid)}\n onToggle={toggleChannel}\n AvatarComponent={Avatar}\n />\n ))\n )}\n </div>\n\n {/* Results feedback */}\n {results && (\n <div className=\"ermis-forward-modal__results\">\n {results.success.length > 0 && (\n <div className=\"ermis-forward-modal__results-success\">\n ✓ Sent to {results.success.join(', ')}\n </div>\n )}\n {results.failed.length > 0 && (\n <div className=\"ermis-forward-modal__results-failed\">\n ✗ Failed: {results.failed.join(', ')}\n </div>\n )}\n </div>\n )}\n </Modal>\n );\n};\n","import { useState, useMemo, useCallback } from 'react';\nimport type {\n Channel,\n E2eeAttachmentManifest,\n E2eeAttachmentManifestAsset,\n FormatMessageResponse,\n} from '@ermis-network/ermis-chat-sdk';\nimport { createForwardMessagePayload } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { removeAccents, buildUserMap } from '../utils';\nimport { isPendingMember, isSkippedMember } from '../channelRoleUtils';\n\nfunction isE2eeAttachmentManifest(attachment: unknown): attachment is E2eeAttachmentManifest {\n return Boolean(\n attachment &&\n typeof attachment === 'object' &&\n (attachment as E2eeAttachmentManifest).version === 1 &&\n typeof (attachment as E2eeAttachmentManifest).attachment_id === 'string' &&\n Array.isArray((attachment as E2eeAttachmentManifest).assets),\n );\n}\n\nfunction isEffectiveE2ee(channel: Channel | null | undefined): boolean {\n if (!channel) return false;\n return typeof (channel as any)._isEffectiveE2ee === 'function'\n ? (channel as any)._isEffectiveE2ee()\n : channel.data?.mls_enabled === true;\n}\n\nfunction attachmentUrl(attachment: any): string | undefined {\n return attachment?.asset_url || attachment?.image_url || attachment?.url || attachment?.thumb_url;\n}\n\nfunction originalAsset(attachment: E2eeAttachmentManifest): E2eeAttachmentManifestAsset | undefined {\n return attachment.assets.find((asset) => asset.kind === 'original') || attachment.assets[0];\n}\n\nfunction displayString(display: Record<string, unknown> | undefined, key: string): string | undefined {\n const value = display?.[key];\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction displayNumber(display: Record<string, unknown> | undefined, key: string): number | undefined {\n const value = display?.[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction extensionForMimeType(mimeType?: string): string {\n if (!mimeType) return '';\n if (mimeType === 'image/jpeg') return '.jpg';\n if (mimeType === 'image/png') return '.png';\n if (mimeType === 'image/webp') return '.webp';\n if (mimeType === 'image/gif') return '.gif';\n if (mimeType === 'video/mp4') return '.mp4';\n if (mimeType === 'video/quicktime') return '.mov';\n if (mimeType === 'video/webm') return '.webm';\n if (mimeType === 'audio/mpeg') return '.mp3';\n if (mimeType === 'audio/webm') return '.webm';\n return '';\n}\n\nfunction inferAttachmentType(attachment: any, mimeType?: string): string | undefined {\n const explicitType = attachment?.attachment_type || attachment?.type;\n if (explicitType === 'voiceRecording') return 'voiceRecording';\n if (explicitType === 'image' || explicitType === 'video' || explicitType === 'file') return explicitType;\n if (mimeType?.startsWith('image/')) return 'image';\n if (mimeType?.startsWith('video/')) return 'video';\n if (mimeType?.startsWith('audio/')) return 'file';\n return undefined;\n}\n\nfunction sourceAttachmentMetadata(\n attachment: any,\n blob: Blob,\n index: number,\n): { file: File; displayOverride: Record<string, unknown> } {\n const manifestDisplay = isE2eeAttachmentManifest(attachment) ? originalAsset(attachment)?.display : undefined;\n const sourceName =\n displayString(manifestDisplay, 'name') ||\n attachment?.file_name ||\n attachment?.title ||\n attachment?.name ||\n `forwarded-attachment-${index + 1}`;\n const sourceMime =\n displayString(manifestDisplay, 'mime_type') ||\n attachment?.mime_type ||\n attachment?.content_type ||\n blob.type ||\n 'application/octet-stream';\n const hasExtension = /\\.[A-Za-z0-9]{1,8}$/.test(sourceName);\n const name = hasExtension ? sourceName : `${sourceName}${extensionForMimeType(sourceMime)}`;\n const normalizedBlob = new File([blob], name, { type: sourceMime || blob.type || 'application/octet-stream' });\n const attachmentType = inferAttachmentType(attachment, sourceMime);\n const width = displayNumber(manifestDisplay, 'width') || attachment?.original_width || attachment?.width;\n const height = displayNumber(manifestDisplay, 'height') || attachment?.original_height || attachment?.height;\n const duration = displayNumber(manifestDisplay, 'duration') || attachment?.duration;\n const displayOverride: Record<string, unknown> = {\n name,\n mime_type: sourceMime,\n size: blob.size,\n ...(attachmentType ? { attachment_type: attachmentType } : {}),\n ...(typeof width === 'number' && Number.isFinite(width) ? { width } : {}),\n ...(typeof height === 'number' && Number.isFinite(height) ? { height } : {}),\n ...(typeof duration === 'number' && Number.isFinite(duration) ? { duration } : {}),\n };\n return { file: normalizedBlob, displayOverride };\n}\n\nasync function materializeForwardSourceAttachments(\n manager: any,\n sourceChannel: Channel,\n sourceAttachments: any[],\n): Promise<{ files: File[]; displayOverrides: Map<number, Record<string, unknown>> }> {\n if (!manager?.initialized) throw new Error('E2EE forward requires an initialized encryption manager');\n const files: File[] = [];\n const displayOverrides = new Map<number, Record<string, unknown>>();\n\n for (const [index, attachment] of sourceAttachments.entries()) {\n let sourceBlob: Blob;\n if (isE2eeAttachmentManifest(attachment)) {\n sourceBlob = await manager.downloadE2eeAttachmentAsset(\n sourceChannel.type,\n sourceChannel.id!,\n attachment,\n 'original',\n );\n } else {\n const url = attachmentUrl(attachment);\n if (!url) throw new Error('Forward source attachment has no downloadable URL');\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Forward source attachment download failed: HTTP ${response.status}`);\n sourceBlob = await response.blob();\n }\n const { file, displayOverride } = sourceAttachmentMetadata(attachment, sourceBlob, index);\n files.push(file);\n displayOverrides.set(index, displayOverride);\n }\n\n return { files, displayOverrides };\n}\n\nexport function useForwardMessage(message: FormatMessageResponse, onDismiss: () => void) {\n const { client, activeChannel } = useChatClient();\n const [selectedChannels, setSelectedChannels] = useState<Set<string>>(new Set());\n const [search, setSearch] = useState('');\n const [sending, setSending] = useState(false);\n const [results, setResults] = useState<{ success: string[]; failed: string[] } | null>(null);\n\n /* ---------- Get channels from client state (include topics) ---------- */\n const channels = useMemo(() => {\n return (Object.values(client.activeChannels) as Channel[]).filter((ch) => {\n const role = ch.state?.membership?.channel_role as string;\n return !isPendingMember(role) && !isSkippedMember(role);\n });\n }, [client.activeChannels]);\n\n /* ---------- Filter by search ---------- */\n const filteredChannels = useMemo(() => {\n if (!search.trim()) return channels;\n const q = search.toLowerCase();\n const cleanQ = removeAccents(q);\n const isStrict = q !== cleanQ;\n\n const result: Channel[] = [];\n for (const ch of channels) {\n const name = (ch.data?.name || ch.cid) as string;\n const t = name.toLowerCase();\n const cleanT = removeAccents(t);\n\n const parentCid = ch.data?.parent_cid as string | undefined;\n const parent = parentCid ? client.activeChannels[parentCid] : null;\n const parentName = parent?.data?.name || '';\n const pt = parentName.toLowerCase();\n const cleanPT = removeAccents(pt);\n\n let matched = false;\n if (isStrict) {\n // Strict match when query has accents\n matched = t.startsWith(q) || pt.startsWith(q);\n } else {\n // Broad match when query is accent-less\n matched = cleanT.startsWith(cleanQ) || cleanPT.startsWith(cleanQ);\n }\n\n if (matched) {\n result.push(ch);\n if (result.length >= 50) break;\n }\n }\n return result;\n }, [channels, search, client.activeChannels]);\n\n /* ---------- Toggle selection ---------- */\n const toggleChannel = useCallback((channel: Channel) => {\n setSelectedChannels((prev) => {\n const next = new Set(prev);\n if (next.has(channel.cid)) {\n next.delete(channel.cid);\n } else {\n next.add(channel.cid);\n }\n return next;\n });\n }, []);\n\n /* ---------- Send forward ---------- */\n const handleSend = useCallback(async () => {\n if (!activeChannel || selectedChannels.size === 0 || sending) return;\n setSending(true);\n const success: string[] = [];\n const failed: string[] = [];\n let queuedBackgroundForward = false;\n\n // Format message text to replace mention IDs with names\n let formattedMessage = { ...message };\n if (formattedMessage.text && formattedMessage.mentioned_users && formattedMessage.mentioned_users.length > 0) {\n let newText = formattedMessage.text;\n const userMap = buildUserMap(activeChannel.state);\n\n formattedMessage.mentioned_users.forEach((userId) => {\n const name = userMap[userId] || client.state.users[userId]?.name || userId;\n newText = newText.replace(new RegExp(`@${userId}`, 'g'), `@${name}`);\n });\n formattedMessage.text = newText;\n }\n\n for (const cid of selectedChannels) {\n const targetChannel = channels.find((c) => c.cid === cid);\n if (!targetChannel) continue;\n try {\n if (!['messaging', 'team', 'topic'].includes(activeChannel.type)) {\n throw new Error('Forward source channel type is not allowed');\n }\n if (formattedMessage.quoted_message_id || formattedMessage.parent_id) {\n throw new Error('Reply/thread messages cannot be forwarded');\n }\n if (formattedMessage.mentioned_all || (formattedMessage.mentioned_users?.length || 0) > 0) {\n throw new Error('Mention messages cannot be forwarded');\n }\n const targetIsE2ee = isEffectiveE2ee(targetChannel);\n const sourceIsE2ee = isEffectiveE2ee(activeChannel);\n if (sourceIsE2ee && !targetIsE2ee) {\n const accepted =\n typeof window === 'undefined' ||\n window.confirm('Forwarding this encrypted message to a standard channel will remove E2EE protection.');\n if (!accepted) throw new Error('Privacy downgrade canceled');\n }\n const forwardPayload = createForwardMessagePayload(\n formattedMessage,\n targetChannel.cid as string,\n activeChannel.cid as string,\n );\n\n const sourceAttachments = (formattedMessage.attachments as any[] | undefined) || [];\n if (targetIsE2ee && sourceAttachments.length > 0) {\n const { files, displayOverrides } = await materializeForwardSourceAttachments(\n client.encryptionManager,\n activeChannel,\n sourceAttachments,\n );\n await (targetChannel as any).enqueueE2eeAttachmentMessage(forwardPayload, files, { displayOverrides });\n queuedBackgroundForward = true;\n } else {\n const standardForwardPayload = { ...forwardPayload };\n if (!targetIsE2ee && sourceIsE2ee && sourceAttachments.length > 0) {\n const { files } = await materializeForwardSourceAttachments(\n client.encryptionManager,\n activeChannel,\n sourceAttachments,\n );\n const { attachments, failedFiles } = await targetChannel.uploadAndPrepareAttachments(files);\n if (failedFiles.length > 0) {\n throw new Error(`Forward standard attachment upload failed for ${failedFiles.length} file(s)`);\n }\n standardForwardPayload.attachments = attachments as any;\n }\n await targetChannel.forwardMessage(standardForwardPayload, {\n type: targetChannel.type,\n channelID: targetChannel.id!,\n });\n }\n success.push((targetChannel.data?.name || targetChannel.cid) as string);\n } catch (err) {\n console.error(`Failed to forward to ${cid}`, err);\n failed.push((targetChannel.data?.name || targetChannel.cid) as string);\n }\n }\n\n setResults({ success, failed });\n setSending(false);\n\n // Auto-close after success (short delay)\n if (failed.length === 0) {\n setTimeout(() => onDismiss(), queuedBackgroundForward ? 0 : 1200);\n }\n }, [client, activeChannel, selectedChannels, channels, message, sending, onDismiss]);\n\n return {\n search,\n setSearch,\n selectedChannels,\n toggleChannel,\n sending,\n results,\n setResults,\n filteredChannels,\n handleSend,\n };\n}\n","import React, { useMemo, useState, useEffect, useContext } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelHeaderProps } from '../types';\nimport type { OnlineStatus } from '../hooks/useOnlineStatus';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport { hasTopicsEnabled, isDirectChannel } from '../channelTypeUtils';\nimport { isSkippedMember, isFriendChannel } from '../channelRoleUtils';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\n\nexport type { ChannelHeaderProps } from '../types';\n\n/**\n * ChannelHeader displays the active channel's avatar and name.\n *\n * Customization:\n * - `title` / `image` — override the channel name and avatar\n * - `subtitle` — add a subtitle line (e.g. member count)\n * - `AvatarComponent` — replace the avatar\n * - `renderTitle(channel)` — fully custom title rendering\n * - `renderRight(channel)` — render content on the right side\n * - `showOnlineStatus` — show online/offline dot for friend channels (default: true)\n * - `OnlineIndicatorComponent` — replace the default indicator\n *\n * For a fully custom header, use `Channel`'s `HeaderComponent` prop instead.\n */\nexport const ChannelHeader: React.FC<ChannelHeaderProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n title,\n image,\n subtitle,\n renderRight,\n renderTitle,\n renderAudioCallButton,\n renderVideoCallButton,\n audioCallTitle = 'Audio Call',\n videoCallTitle = 'Video Call',\n CallBadgeComponent,\n showOnlineStatus = true,\n onlineLabel = 'Online',\n offlineLabel = 'Offline',\n OnlineIndicatorComponent,\n}) => {\n const { activeChannel, client, enableCall } = useChatClient();\n const { isPending } = usePendingState(activeChannel, client.userID);\n const callContext = useContext(ErmisCallContext);\n\n const isSkipped = client.userID\n ? isSkippedMember(activeChannel?.state?.members?.[client.userID]?.channel_role as string) ||\n isSkippedMember(activeChannel?.state?.membership?.channel_role as string)\n : false;\n\n const actionDisabled = isPending || isSkipped;\n\n // Force re-render when channel.updated WS event fires\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!activeChannel) return;\n const handleUpdate = () => setChannelUpdateCount((c) => c + 1);\n\n const sub1 = activeChannel.on('channel.updated', handleUpdate);\n\n // Also listen for client-level notifications that might affect this channel's roles/members\n // We only care about this for messaging (direct) channels to update online status\n const sub2 = client.on('notification.invite_accepted', (event) => {\n if (event.cid === activeChannel.cid && isDirectChannel(activeChannel)) {\n handleUpdate();\n }\n });\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [activeChannel, client]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelName = useMemo(() =>\n title || activeChannel?.data?.name || activeChannel?.cid || '',\n [title, activeChannel?.data?.name, activeChannel?.cid, channelUpdateCount],\n );\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelImage = useMemo(() =>\n image || (activeChannel?.data?.image as string | undefined),\n [image, activeChannel?.data?.image, channelUpdateCount],\n );\n\n const teamName = undefined;\n\n // ── Online Status (direct friend channels only) ──\n const currentUserId = client.userID;\n\n // Get the \"other\" user's ID from the direct channel.\n const otherUserId = useMemo(() => {\n if (!activeChannel || !currentUserId || !isDirectChannel(activeChannel)) return undefined;\n const members = activeChannel.state?.members;\n if (!members) return undefined;\n for (const memberId of Object.keys(members)) {\n if (memberId !== currentUserId) return memberId;\n }\n return undefined;\n }, [activeChannel, currentUserId, channelUpdateCount]);\n\n // Check if this is a friend channel (both members are owner).\n const isFriend = useMemo(() => {\n if (!otherUserId || !currentUserId || !activeChannel) return false;\n return isFriendChannel(activeChannel, otherUserId, currentUserId);\n }, [activeChannel, otherUserId, currentUserId, channelUpdateCount]);\n\n // Derive online status from watchers + subscribe to realtime events.\n const [onlineStatus, setOnlineStatus] = useState<OnlineStatus>('unknown');\n\n useEffect(() => {\n if (!showOnlineStatus || !isFriend || !otherUserId || !activeChannel) {\n setOnlineStatus('unknown');\n return;\n }\n\n // Read initial state from watchers.\n setOnlineStatus(activeChannel.state?.watchers?.[otherUserId] ? 'online' : 'offline');\n\n const handleWatchingStart = (event: Event) => {\n if (event.user?.id === otherUserId) {\n setOnlineStatus('online');\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n if (event.user?.id === otherUserId) {\n setOnlineStatus('offline');\n }\n };\n\n const sub1 = activeChannel.on('user.watching.start', handleWatchingStart);\n const sub2 = activeChannel.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [activeChannel, otherUserId, isFriend, showOnlineStatus]);\n\n const showOnlineDot = showOnlineStatus && onlineStatus !== 'unknown';\n const isOnline = onlineStatus === 'online';\n\n if (!activeChannel) return null;\n\n return (\n <div className={`ermis-channel-header${className ? ` ${className}` : ''}`}>\n {activeChannel.data?.parent_cid ? (\n <div className=\"ermis-channel-header__topic-avatar\">\n {channelImage && typeof channelImage === 'string' && channelImage.startsWith('emoji://')\n ? channelImage.replace('emoji://', '')\n : '#'}\n </div>\n ) : (\n <AvatarComponent image={channelImage} name={teamName || channelName} size={44} />\n )}\n\n <div className=\"ermis-channel-header__info\">\n {renderTitle ? (\n renderTitle(activeChannel)\n ) : (\n <div className=\"ermis-channel-header__title-container\">\n <div className=\"ermis-channel-header__name\">{channelName}</div>\n </div>\n )}\n {/* Online/Offline indicator for friend direct channels */}\n {showOnlineDot && (\n OnlineIndicatorComponent ? (\n <OnlineIndicatorComponent isOnline={isOnline} />\n ) : (\n <div className={`ermis-channel-header__online-status ermis-channel-header__online-status--${isOnline ? 'online' : 'offline'}`}>\n <span className={`ermis-channel-header__online-dot ermis-channel-header__online-dot--${isOnline ? 'online' : 'offline'}`} />\n <span className=\"ermis-channel-header__online-label\">\n {isOnline ? onlineLabel : offlineLabel}\n </span>\n </div>\n )\n )}\n {/* Consumer-provided subtitle (takes over if set) */}\n {subtitle && !showOnlineDot && (\n <div className=\"ermis-channel-header__subtitle\">{subtitle}</div>\n )}\n </div>\n\n {/* renderRight exposes actionDisabled for consumers to disable UI features natively */}\n <div className=\"ermis-channel-header__actions\">\n {enableCall && callContext && isDirectChannel(activeChannel) && !isPending && !isSkipped && (\n <>\n {renderAudioCallButton ? (\n renderAudioCallButton(() => callContext.createCall('audio', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('audio', activeChannel.cid || '')}\n title={audioCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n </button>\n )}\n\n {renderVideoCallButton ? (\n renderVideoCallButton(() => callContext.createCall('video', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('video', activeChannel.cid || '')}\n title={videoCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n </button>\n )}\n </>\n )}\n {/* C8: Active call badge */}\n {enableCall && callContext && callContext.callStatus && CallBadgeComponent && (\n <CallBadgeComponent callType={callContext.callType} />\n )}\n {renderRight && renderRight(activeChannel, actionDisabled)}\n </div>\n </div>\n );\n});\n\nChannelHeader.displayName = 'ChannelHeader';\n","import React, { useState, useRef, useCallback, useMemo, useEffect, useLayoutEffect } from 'react';\nimport { VList as _VList, type VListHandle } from 'virtua';\n\n// Workaround for React 19 JSX element type mismatch with virtua's VList\nconst VList = _VList as any;\nimport type { MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useLoadMessages } from '../hooks/useLoadMessages';\nimport { useScrollToMessage } from '../hooks/useScrollToMessage';\nimport { useChannelMessages } from '../hooks/useChannelMessages';\nimport { useChannelProfile } from '../hooks/useChannelData';\nimport { Avatar } from './Avatar';\nimport { MessageItem } from './MessageItem';\nimport { SystemMessageItem } from './MessageItem';\nimport { isPublicGroupChannel, isDirectChannel } from '../channelTypeUtils';\nimport { canManageChannel, isSkippedMember, isPendingMember } from '../channelRoleUtils';\nimport {\n defaultMessageRenderers,\n type MessageBubbleProps,\n} from './MessageRenderers';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport { getDateKey, formatDateLabel, getMessageUserId, formatReadTimestamp } from '../utils';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { PinnedMessages } from './PinnedMessages';\nimport { ReadReceipts } from './ReadReceipts';\nimport { TypingIndicator } from './TypingIndicator';\nimport { PendingOverlay } from './PendingOverlay';\nimport { SkippedOverlay } from './SkippedOverlay';\nimport { BannedOverlay } from './BannedOverlay';\nimport { ClosedTopicOverlay } from './ClosedTopicOverlay';\nimport type { MessageListProps } from '../types';\n\n/* ----------------------------------------------------------\n Internal sub-components\n ---------------------------------------------------------- */\nconst DefaultDateSeparator: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-message-list__date-separator\">\n <div className=\"ermis-message-list__date-separator-line\" />\n <span className=\"ermis-message-list__date-separator-label\">{label}</span>\n <div className=\"ermis-message-list__date-separator-line\" />\n </div>\n));\n(DefaultDateSeparator as any).displayName = 'DefaultDateSeparator';\n\n/** Time gap threshold in ms: messages more than 5 minutes apart get a time separator */\nconst TIME_GAP_THRESHOLD_MS = 5 * 60 * 1000;\n\nfunction getTimestamp(date: Date | string | undefined): number {\n if (!date) return 0;\n return date instanceof Date ? date.getTime() : new Date(date).getTime();\n}\n\nfunction formatTimeSeparator(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\nconst DefaultJumpToLatest = React.memo(({ onClick, label = '↓ Jump to latest' }: any) => (\n <button className=\"ermis-message-list__jump-latest\" onClick={onClick}>\n {label}\n </button>\n));\nDefaultJumpToLatest.displayName = 'DefaultJumpToLatest';\n\nconst DefaultEmpty = React.memo(({ title = 'No messages yet', subtitle = 'Send a message to start the conversation' }: any) => (\n <div className=\"ermis-message-list__empty\">\n <div className=\"ermis-message-list__empty-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__empty-title\">{title}</span>\n <span className=\"ermis-message-list__empty-subtitle\">{subtitle}</span>\n </div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\nconst DefaultBubble: React.FC<MessageBubbleProps> = React.memo(({\n isOwnMessage,\n message,\n children,\n}) => (\n <div\n className={`ermis-message-bubble ${isOwnMessage ? 'ermis-message-bubble--own' : 'ermis-message-bubble--other'}`}\n >\n {message?.pinned && (\n <div className={`ermis-message-list__pinned-indicator ${isOwnMessage ? 'ermis-message-list__pinned-indicator--own' : 'ermis-message-list__pinned-indicator--other'}`}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </div>\n )}\n {children}\n </div>\n));\n(DefaultBubble as any).displayName = 'DefaultBubble';\n\nconst DefaultPendingInviteeNotification = React.memo(({ inviteeName, label }: { inviteeName?: string, label?: string }) => {\n const defaultLabel = inviteeName ? `${inviteeName} needs to accept your invitation to see the messages you've sent` : 'The invited user needs to accept your invitation to see the messages you\\'ve sent';\n return (\n <div className=\"ermis-message-list__pending-invitee\">\n <div className=\"ermis-message-list__pending-invitee-content\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n <span>{label || defaultLabel}</span>\n </div>\n </div>\n );\n});\nDefaultPendingInviteeNotification.displayName = 'DefaultPendingInviteeNotification';\n\n/* ----------------------------------------------------------\n VirtualMessageList\n ---------------------------------------------------------- */\nexport const VirtualMessageList: React.FC<MessageListProps> = React.memo(({\n renderMessage,\n className,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n MessageBubble = DefaultBubble,\n messageRenderers: customRenderers,\n loadMoreLimit = 25,\n DateSeparatorComponent = DefaultDateSeparator,\n dateLocale,\n MessageItemComponent = MessageItem,\n SystemMessageItemComponent = SystemMessageItem,\n JumpToLatestButton = DefaultJumpToLatest,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent,\n showPinnedMessages = true,\n PinnedMessagesComponent = PinnedMessages,\n showReadReceipts = true,\n ReadReceiptsComponent = ReadReceipts,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars = 5,\n showTypingIndicator = true,\n TypingIndicatorComponent = TypingIndicator,\n MessageReactionsComponent,\n emptyTitle = 'No messages yet',\n emptySubtitle = 'Send a message to start the conversation',\n jumpToLatestLabel = '↓ Jump to latest',\n bannedOverlayTitle = 'You have been banned from this channel',\n bannedOverlaySubtitle = 'You can no longer read or send messages here',\n blockedOverlayTitle = 'You have blocked this user',\n blockedOverlaySubtitle = 'Unblock to continue the conversation',\n pendingOverlayTitle = 'You are invited to this channel',\n pendingOverlaySubtitle = 'Accept the invitation to view messages and interact',\n pendingAcceptLabel = 'Accept',\n pendingRejectLabel = 'Reject',\n pendingSkipLabel = 'Skip',\n skippedOverlayTitle = 'You skipped this conversation',\n skippedOverlaySubtitle = 'Accept the invitation to start chatting',\n skippedAcceptLabel = 'Accept',\n closedTopicOverlayTitle = 'This topic has been closed',\n closedTopicOverlaySubtitle = 'You can no longer read or send messages in this topic.',\n closedTopicReopenLabel = 'Reopen Topic',\n PendingInviteeNotificationComponent = DefaultPendingInviteeNotification,\n pendingInviteeLabel,\n pinnedMessagesLabel,\n seeAllLabel,\n collapseLabel,\n unpinLabel,\n stickerLabel,\n attachmentLabel = 'Attachment',\n unavailableMessageLabel = 'Message unavailable',\n encryptedMessageLabel,\n encryptedMessageFailedLabel,\n encryptedMessageDecryptingLabel,\n encryptedMessageUnavailableLabel,\n typingIndicatorLabel,\n deletedMessageLabel = 'This message was deleted',\n systemMessageTranslations,\n signalMessageTranslations,\n includeHiddenMessages = true,\n onMentionClick,\n onUserNameClick,\n onAddReactionClick,\n}) => {\n const { client, messages, readState, activeChannel, setActiveChannel, jumpToMessageId, setJumpToMessageId } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending, inviteUpdateCount } = usePendingState(activeChannel, client.userID);\n\n const isSkipped = client.userID\n ? isSkippedMember(activeChannel?.state?.members?.[client.userID]?.channel_role as string) ||\n isSkippedMember(activeChannel?.state?.membership?.channel_role as string)\n : false;\n\n const isClosedTopic = activeChannel?.data?.is_closed_topic === true;\n const parentCid = activeChannel?.data?.parent_cid as string | undefined;\n const parentChannel = parentCid && client ? client.activeChannels[parentCid] : undefined;\n\n const { channelName, channelImage } = useChannelProfile(activeChannel);\n\n const vlistRef = useRef<VListHandle>(null);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const currentUserId = client.userID;\n const currentUserRole = currentUserId ? activeChannel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const canManageTopic = canManageChannel(currentUserRole);\n\n const pendingInviteeName = useMemo(() => {\n if (!activeChannel || !currentUserId) return null;\n if (!isDirectChannel(activeChannel)) return null;\n const membersList = Object.values(activeChannel.state?.members || {});\n if (membersList.length === 2 && !isPending) {\n const otherUser = membersList.find(m => m.user_id !== currentUserId);\n if (otherUser && isPendingMember(otherUser.channel_role)) {\n return otherUser.user?.name || otherUser.user?.id || 'User';\n }\n }\n return null;\n }, [activeChannel, currentUserId, isPending, inviteUpdateCount]);\n\n // Ref to scope DOM queries (safe for multiple instances)\n const containerRef = useRef<HTMLDivElement>(null);\n const getVListElement = useCallback((): HTMLElement | null => {\n return containerRef.current?.querySelector('.ermis-message-list__vlist') ?? null;\n }, []);\n\n const handleAcceptInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n let action: 'join' | 'accept' = 'accept';\n if (isPublicGroupChannel(activeChannel)) {\n const isMember = !!(currentUserId && activeChannel.state?.members?.[currentUserId]);\n action = isMember ? 'accept' : 'join';\n }\n await activeChannel.acceptInvite(action);\n\n // Optimistically update local membership so React picks up the change immediately.\n // The async _handleChannelEvent in the SDK races with client listeners,\n // so the WS event alone is not reliable for updating React state in time.\n if (activeChannel.state && currentUserId) {\n const updatedMembership = {\n ...activeChannel.state.membership,\n channel_role: 'member',\n user_id: currentUserId,\n } as Record<string, unknown>;\n activeChannel.state.membership = updatedMembership;\n\n if (activeChannel.state.members?.[currentUserId]) {\n activeChannel.state.members[currentUserId] = {\n ...activeChannel.state.members[currentUserId],\n channel_role: 'member',\n };\n }\n\n // Dispatch synthetic event so all React listeners update\n const clientObj = activeChannel.getClient();\n const eventType = action === 'join' ? 'member.joined' : 'notification.invite_accepted';\n clientObj.dispatchEvent({\n type: eventType,\n cid: activeChannel.cid,\n channel_type: activeChannel.type,\n channel_id: activeChannel.id,\n channel: activeChannel.data,\n member: updatedMembership,\n user: clientObj.user,\n } as any);\n }\n\n } catch (e: any) {\n console.error('Error accepting invite', e);\n }\n }, [activeChannel, currentUserId]);\n\n const handleRejectInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.rejectInvite();\n if (setActiveChannel) setActiveChannel(null);\n } catch (e: any) {\n console.error('Error rejecting invite', e);\n }\n }, [activeChannel, setActiveChannel]);\n\n const handleSkipInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.skipInvite();\n if (setActiveChannel) setActiveChannel(null);\n } catch (e: any) {\n console.error('Error skipping invite', e);\n }\n }, [activeChannel, setActiveChannel]);\n\n const elementsCountRef = useRef(0);\n\n const scrollToBottom = useCallback((smooth = false, attempts = 0) => {\n const handle = vlistRef.current;\n if (!handle) return;\n\n const count = elementsCountRef.current;\n if (count === 0) return;\n\n // Ensure virtua has measured the viewport via ResizeObserver.\n // If viewportSize is unmeasured (0) or scrollSize is 0, align: 'end' calculates wrong.\n if ((!handle.viewportSize || handle.viewportSize === 0) && attempts < 10) {\n requestAnimationFrame(() => scrollToBottom(smooth, attempts + 1));\n return;\n }\n\n if (!smooth && handle.scrollSize > handle.viewportSize) {\n handle.scrollTo(Math.max(0, handle.scrollSize - handle.viewportSize));\n }\n handle.scrollToIndex(count - 1, { align: 'end', smooth });\n }, []);\n\n // Shared guard: skip scroll-triggered loads during jump transitions\n const jumpingRef = useRef(false);\n const scrollLoadLockRef = useRef(false);\n const scrollLoadLockTokenRef = useRef(0);\n const holdScrollLoadLock = useCallback((duration = 750) => {\n const token = scrollLoadLockTokenRef.current + 1;\n scrollLoadLockTokenRef.current = token;\n scrollLoadLockRef.current = true;\n setTimeout(() => {\n if (scrollLoadLockTokenRef.current === token) {\n scrollLoadLockRef.current = false;\n }\n }, duration);\n }, []);\n\n /* ---------- Hooks ---------- */\n const {\n shiftMode,\n hasMore, setHasMore,\n hasNewer, setHasNewer,\n loadingMoreRef, loadingNewerRef,\n handleScroll,\n isAtBottomRef,\n } = useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n scrollLoadLockRef,\n loadMoreLimit,\n });\n\n const isNearBottom = useCallback(() => {\n const handle = vlistRef.current;\n if (!handle) return isAtBottomRef.current;\n\n const { scrollOffset, scrollSize, viewportSize } = handle;\n if (!Number.isFinite(scrollOffset) || !Number.isFinite(scrollSize) || !Number.isFinite(viewportSize)) {\n return isAtBottomRef.current;\n }\n if (scrollSize <= viewportSize || viewportSize <= 0) return true;\n\n return scrollSize - (scrollOffset + viewportSize) <= 160;\n }, [isAtBottomRef]);\n\n const { highlightedId, scrollToMessage, jumpToLatest } = useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n });\n\n // React to jumpToMessageId from context (e.g. search panel)\n useEffect(() => {\n if (jumpToMessageId) {\n scrollToMessage(jumpToMessageId);\n setJumpToMessageId(null);\n }\n }, [jumpToMessageId, scrollToMessage, setJumpToMessageId]);\n\n useChannelMessages({\n scrollToBottom,\n isNearBottom,\n holdScrollLoadLock,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch: useCallback(() => {\n setHasMore(true);\n setHasNewer(false);\n loadingMoreRef.current = false;\n loadingNewerRef.current = false;\n }, [setHasMore, setHasNewer]),\n includeHiddenMessages,\n containerRef,\n });\n\n const lastAutoScrollKeyRef = useRef<string | null>(null);\n\n useLayoutEffect(() => {\n const lastMessage = messages[messages.length - 1];\n if (!lastMessage?.id || !currentUserId) return;\n\n const key = `${activeChannel?.cid || ''}:${lastMessage.id}`;\n if (lastAutoScrollKeyRef.current === key) return;\n\n const isOwnLastMessage =\n lastMessage.user_id === currentUserId || lastMessage.user?.id === currentUserId;\n if (!isOwnLastMessage && !isAtBottomRef.current && !isNearBottom()) return;\n if (!isOwnLastMessage && jumpingRef.current) return;\n if (loadingMoreRef.current || loadingNewerRef.current) return;\n\n lastAutoScrollKeyRef.current = key;\n isAtBottomRef.current = true;\n holdScrollLoadLock(750);\n\n scrollToBottom(false);\n requestAnimationFrame(() => {\n requestAnimationFrame(() => scrollToBottom(false));\n });\n setTimeout(() => scrollToBottom(false), 80);\n setTimeout(() => scrollToBottom(false), 180);\n setTimeout(() => scrollToBottom(false), 360);\n }, [activeChannel?.cid, currentUserId, messages, scrollToBottom, isNearBottom, holdScrollLoadLock]);\n\n const hasOverlay = Boolean(isClosedTopic || isPending || isBanned || isBlocked || isSkipped);\n const prevOverlayRef = useRef(hasOverlay);\n\n useEffect(() => {\n if (prevOverlayRef.current && !hasOverlay) {\n // Transitioned from having an overlay to normal view.\n // Give VList a moment to measure its new DOM size via ResizeObserver, then jump to the bottom.\n setTimeout(() => scrollToBottom(false), 50);\n setTimeout(() => scrollToBottom(false), 200);\n setTimeout(() => scrollToBottom(false), 500);\n }\n prevOverlayRef.current = hasOverlay;\n }, [hasOverlay, scrollToBottom]);\n\n const renderers = useMemo(\n () => ({ ...defaultMessageRenderers, ...customRenderers }),\n [customRenderers],\n );\n\n /* ---------- Compute read-by map (message.id → readers) ---------- */\n const readByMap = useMemo(() => {\n const map: Record<string, Array<{ id: string; name?: string; avatar?: string; last_read?: Date | string }>> = {};\n if (!readState) return map;\n for (const userId of Object.keys(readState)) {\n if (userId === currentUserId) continue; // exclude self\n const entry = readState[userId];\n if (entry.last_read_message_id) {\n if (!map[entry.last_read_message_id]) {\n map[entry.last_read_message_id] = [];\n }\n map[entry.last_read_message_id].push({\n id: userId,\n name: entry.user?.name,\n avatar: entry.user?.avatar,\n last_read: entry.last_read,\n });\n }\n }\n return map;\n }, [readState, currentUserId]);\n\n /* ---------- Memoized message elements ---------- */\n const messageElements = useMemo(() => {\n const elements: React.ReactNode[] = [];\n\n // Pre-compute per-message data\n type MsgEntry = {\n message: typeof messages[0];\n index: number;\n isOwnMessage: boolean;\n messageType: MessageLabel;\n showDateSeparator: boolean;\n isFirstInGroup: boolean;\n isLastInGroup: boolean;\n validReaders: Array<{ id: string; name?: string; avatar?: string; last_read?: Date | string }>;\n hasReaders: boolean;\n };\n const entries: MsgEntry[] = messages.map((message, index) => {\n const isOwnMessage =\n message.user_id === currentUserId || message.user?.id === currentUserId;\n const messageType = (\n isStickerMessage(message) ? 'sticker' : (message.type || 'regular')\n ) as MessageLabel;\n\n // Date separator\n const prevMsg = index > 0 ? messages[index - 1] : null;\n const showDateSeparator =\n !prevMsg || getDateKey(message.created_at) !== getDateKey(prevMsg.created_at);\n const prevType = (prevMsg?.type || 'regular') as MessageLabel;\n const prevTimeGap = prevMsg\n ? Math.abs(getTimestamp(message.created_at) - getTimestamp(prevMsg.created_at)) > TIME_GAP_THRESHOLD_MS\n : false;\n const isFirstInGroup =\n showDateSeparator ||\n !prevMsg ||\n prevType === 'system' ||\n prevType === 'signal' ||\n getMessageUserId(prevMsg) !== getMessageUserId(message) ||\n prevTimeGap;\n const nextMsg = index < messages.length - 1 ? messages[index + 1] : null;\n const nextType = (nextMsg?.type || 'regular') as MessageLabel;\n const nextShowDateSeparator = nextMsg\n ? getDateKey(nextMsg.created_at) !== getDateKey(message.created_at)\n : false;\n const validReaders = message.id && readByMap[message.id] ? readByMap[message.id].filter(r => r.id !== getMessageUserId(message)) : [];\n const hasReaders = showReadReceipts && validReaders.length > 0;\n const nextTimeGap = nextMsg\n ? Math.abs(getTimestamp(nextMsg.created_at) - getTimestamp(message.created_at)) > TIME_GAP_THRESHOLD_MS\n : false;\n const isLastInGroup =\n !nextMsg ||\n nextShowDateSeparator ||\n nextType === 'system' ||\n nextType === 'signal' ||\n getMessageUserId(nextMsg) !== getMessageUserId(message) ||\n nextTimeGap;\n return { message, index, isOwnMessage, messageType, showDateSeparator, isFirstInGroup, isLastInGroup, validReaders, hasReaders };\n });\n\n // Build groups: consecutive regular messages from same user\n let i = 0;\n while (i < entries.length) {\n const entry = entries[i];\n\n // Date separator before any message\n if (entry.showDateSeparator) {\n elements.push(\n <div key={`date-${getDateKey(entry.message.created_at)}`}>\n <DateSeparatorComponent label={formatDateLabel(entry.message.created_at, dateLocale)} />\n </div>\n );\n }\n\n // Custom renderMessage\n if (renderMessage) {\n elements.push(\n <div key={entry.message.id || `msg-${entry.index}`}>\n <div>{renderMessage(entry.message, entry.isOwnMessage)}</div>\n </div>\n );\n i++;\n continue;\n }\n\n // System messages — standalone\n if (entry.messageType === 'system') {\n elements.push(\n <div key={entry.message.id || `msg-${entry.index}`}>\n <SystemMessageItemComponent\n message={entry.message}\n isOwnMessage={entry.isOwnMessage}\n SystemRenderer={renderers.system}\n systemMessageTranslations={systemMessageTranslations}\n />\n </div>\n );\n i++;\n continue;\n }\n\n // Collect consecutive regular/signal messages from the same user into a group\n // Break group on: different user, system message, date separator, or time gap > 5min\n const groupEntries: MsgEntry[] = [entry];\n let j = i + 1;\n while (j < entries.length) {\n const nextEntry = entries[j];\n const prevEntry = entries[j - 1];\n const timeGap = Math.abs(\n getTimestamp(nextEntry.message.created_at) - getTimestamp(prevEntry.message.created_at)\n );\n // Break group if: different user, system message, date separator, or time gap\n if (\n nextEntry.showDateSeparator ||\n nextEntry.messageType === 'system' ||\n getMessageUserId(nextEntry.message) !== getMessageUserId(entry.message) ||\n timeGap > TIME_GAP_THRESHOLD_MS\n ) {\n break;\n }\n groupEntries.push(nextEntry);\n j++;\n }\n\n const isOwn = entry.isOwnMessage;\n const userName = entry.message.user?.name || entry.message.user_id;\n const userAvatar = entry.message.user?.avatar;\n const groupKey = `group-${entry.message.id || `g-${entry.index}`}`;\n\n // Check if we need a time separator BEFORE this group\n // (when previous group was from same user but time gap split them)\n if (i > 0) {\n const prevEntry = entries[i - 1];\n const timeGap = Math.abs(\n getTimestamp(entry.message.created_at) - getTimestamp(prevEntry.message.created_at)\n );\n if (\n !entry.showDateSeparator &&\n prevEntry.messageType !== 'system' &&\n getMessageUserId(prevEntry.message) === getMessageUserId(entry.message) &&\n timeGap > TIME_GAP_THRESHOLD_MS\n ) {\n elements.push(\n <div key={`timesep-${entry.message.id}`}>\n <div className=\"ermis-message-list__time-separator\">\n <span className=\"ermis-message-list__time-separator-label\">\n {formatTimeSeparator(entry.message.created_at)}\n </span>\n </div>\n </div>\n );\n }\n }\n\n // Render group wrapper with sticky avatar\n elements.push(\n <div key={groupKey}>\n <div className={`ermis-message-group ${isOwn ? 'ermis-message-group--own' : 'ermis-message-group--other'}`}>\n {/* Avatar column — sticky for scroll tracking */}\n {!isOwn && (\n <div className=\"ermis-message-group__avatar-col\">\n <AvatarComponent image={userAvatar} name={userName} size={36} />\n </div>\n )}\n {/* Messages column */}\n <div className=\"ermis-message-group__messages-col\">\n {groupEntries.map((ge) => {\n const MessageRenderer = renderers[ge.messageType] || renderers.regular;\n return (\n <React.Fragment key={ge.message.id || `msg-${ge.index}`}>\n {/* Date separators within group (if needed for mid-group entries) */}\n {ge !== entry && ge.showDateSeparator && (\n <DateSeparatorComponent label={formatDateLabel(ge.message.created_at, dateLocale)} />\n )}\n <MessageItemComponent\n message={ge.message}\n isOwnMessage={ge.isOwnMessage}\n isFirstInGroup={ge.isFirstInGroup}\n isLastInGroup={ge.isLastInGroup}\n isHighlighted={highlightedId === ge.message.id}\n AvatarComponent={AvatarComponent}\n MessageBubble={MessageBubble}\n MessageRenderer={MessageRenderer}\n onClickQuote={scrollToMessage}\n QuotedMessagePreviewComponent={QuotedMessagePreviewComponent}\n MessageActionsBoxComponent={MessageActionsBoxComponent}\n MessageReactionsComponent={MessageReactionsComponent}\n deletedMessageLabel={deletedMessageLabel}\n attachmentLabel={attachmentLabel}\n unavailableMessageLabel={unavailableMessageLabel}\n stickerLabel={stickerLabel}\n encryptedMessageLabel={encryptedMessageLabel}\n encryptedMessageFailedLabel={encryptedMessageFailedLabel}\n encryptedMessageDecryptingLabel={encryptedMessageDecryptingLabel}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n onMentionClick={onMentionClick}\n onUserNameClick={onUserNameClick}\n onAddReactionClick={onAddReactionClick}\n hideAvatar\n />\n </React.Fragment>\n );\n })}\n </div>\n </div>\n {/* Read receipts — consolidated: merge all readers in this group into one row */}\n {(() => {\n if (!showReadReceipts) return null;\n const allReaders: Array<{ id: string; name?: string; avatar?: string; last_read?: Date | string }> = [];\n const seen = new Set<string>();\n for (const ge of groupEntries) {\n for (const r of ge.validReaders) {\n if (!seen.has(r.id)) {\n seen.add(r.id);\n allReaders.push(r);\n }\n }\n }\n if (allReaders.length === 0) return null;\n const lastEntry = groupEntries[groupEntries.length - 1];\n return (\n <ReadReceiptsComponent\n key={`receipt-${lastEntry.message.id}`}\n readers={allReaders}\n maxAvatars={readReceiptsMaxAvatars}\n AvatarComponent={AvatarComponent}\n TooltipComponent={ReadReceiptsTooltipComponent}\n isOwnMessage={lastEntry.isOwnMessage}\n isLastInGroup={lastEntry.isLastInGroup}\n status={lastEntry.message.status}\n />\n );\n })()}\n </div>\n );\n\n i = j;\n }\n\n\n elementsCountRef.current = elements.length;\n return elements;\n }, [\n messages,\n currentUserId,\n highlightedId,\n renderers,\n renderMessage,\n AvatarComponent,\n MessageBubble,\n scrollToMessage,\n DateSeparatorComponent,\n MessageItemComponent,\n SystemMessageItemComponent,\n QuotedMessagePreviewComponent,\n MessageActionsBoxComponent,\n MessageReactionsComponent,\n readByMap,\n showReadReceipts,\n ReadReceiptsComponent,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars,\n dateLocale,\n onMentionClick,\n onUserNameClick,\n onAddReactionClick,\n encryptedMessageLabel,\n encryptedMessageFailedLabel,\n encryptedMessageDecryptingLabel,\n ]);\n\n if (isBanned || isBlocked) {\n return (\n <BannedOverlay\n isBlocked={isBlocked}\n blockedTitle={blockedOverlayTitle}\n bannedTitle={bannedOverlayTitle}\n blockedSubtitle={blockedOverlaySubtitle}\n bannedSubtitle={bannedOverlaySubtitle}\n onUnblock={() => { activeChannel?.unblockUser().catch((e: any) => console.error('Error unblocking user', e)); }}\n />\n );\n }\n\n if (isPending) {\n const isDirect = activeChannel ? isDirectChannel(activeChannel) : false;\n return (\n <PendingOverlay\n channelImage={channelImage}\n channelName={channelName}\n title={pendingOverlayTitle}\n subtitle={pendingOverlaySubtitle}\n rejectLabel={pendingRejectLabel}\n acceptLabel={pendingAcceptLabel}\n onReject={handleRejectInvite}\n onAccept={handleAcceptInvite}\n skipLabel={isDirect ? pendingSkipLabel : undefined}\n onSkip={isDirect ? handleSkipInvite : undefined}\n AvatarComponent={AvatarComponent}\n />\n );\n }\n\n if (isSkipped) {\n return (\n <SkippedOverlay\n channelImage={channelImage}\n channelName={channelName}\n title={skippedOverlayTitle}\n subtitle={skippedOverlaySubtitle}\n acceptLabel={skippedAcceptLabel}\n onAccept={handleAcceptInvite}\n AvatarComponent={AvatarComponent}\n />\n );\n }\n\n if (isClosedTopic) {\n return (\n <ClosedTopicOverlay\n title={closedTopicOverlayTitle}\n subtitle={closedTopicOverlaySubtitle}\n canManageTopic={Boolean(canManageTopic && activeChannel && parentChannel)}\n reopenLabel={closedTopicReopenLabel}\n onReopen={() => { parentChannel?.reopenTopic(activeChannel!.cid).catch((e: any) => console.error('Error reopening topic', e)); }}\n />\n );\n }\n\n return (\n <>\n <div ref={containerRef} className={`ermis-message-list${className ? ` ${className}` : ''}`}>\n {showPinnedMessages && (\n <PinnedMessagesComponent\n onClickMessage={scrollToMessage}\n AvatarComponent={AvatarComponent}\n pinnedMessagesLabel={pinnedMessagesLabel}\n seeAllLabel={seeAllLabel}\n collapseLabel={collapseLabel}\n unpinLabel={unpinLabel}\n stickerLabel={stickerLabel}\n attachmentLabel={attachmentLabel}\n unavailableMessageLabel={unavailableMessageLabel}\n />\n )}\n\n {messages.length === 0 && (\n EmptyStateIndicator === DefaultEmpty\n ? <DefaultEmpty title={emptyTitle} subtitle={emptySubtitle} />\n : <EmptyStateIndicator />\n )}\n\n {pendingInviteeName && (\n <PendingInviteeNotificationComponent\n inviteeName={pendingInviteeName}\n label={typeof pendingInviteeLabel === 'function' ? pendingInviteeLabel(pendingInviteeName) : pendingInviteeLabel}\n />\n )}\n\n <VList\n key={activeChannel?.cid || 'empty'}\n ref={vlistRef}\n shift={shiftMode}\n onScroll={handleScroll}\n className=\"ermis-message-list__vlist\"\n >\n {messageElements}\n </VList>\n\n {/* Jump to latest button */}\n {hasNewer && (\n JumpToLatestButton === DefaultJumpToLatest\n ? <DefaultJumpToLatest onClick={jumpToLatest} label={jumpToLatestLabel} />\n : <JumpToLatestButton onClick={jumpToLatest} />\n )}\n </div>\n\n {/* Typing indicator — outside message list, flows between messages and input */}\n {showTypingIndicator && <TypingIndicatorComponent typingIndicatorLabel={typingIndicatorLabel} />}\n </>\n );\n});\n\nVirtualMessageList.displayName = 'VirtualMessageList';\n","import { useState, useRef, useCallback, useEffect } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { useChatClient } from './useChatClient';\n\nconst LOAD_MORE_THRESHOLD = 200;\n\n/** Filter out messages whose id already exists in `existing` (or self-dedup if omitted). */\nexport const dedupMessages = (incoming: any[], existing?: any[]) => {\n const ids = new Set(existing?.map((m) => m.id) ?? []);\n return incoming.filter((m: any) => {\n if (!m.id || ids.has(m.id)) return false;\n ids.add(m.id);\n return true;\n });\n};\n\nexport type UseLoadMessagesOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n /** Shared guard ref — skip scroll-triggered loads during jump transitions */\n jumpingRef: React.MutableRefObject<boolean>;\n /** Blocks scroll-triggered pagination while auto-following appended messages. */\n scrollLoadLockRef?: React.MutableRefObject<boolean>;\n loadMoreLimit?: number;\n};\n\nexport type UseLoadMessagesReturn = {\n /** VList shift mode — true during prepend, auto-resets to false */\n shiftMode: boolean;\n hasMore: boolean;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n hasNewer: boolean;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n hasMoreRef: React.RefObject<boolean>;\n hasNewerRef: React.RefObject<boolean>;\n loadingMoreRef: React.MutableRefObject<boolean>;\n loadingNewerRef: React.MutableRefObject<boolean>;\n loadMore: () => Promise<void>;\n loadNewer: () => Promise<void>;\n handleScroll: (offset: number) => void;\n isAtBottomRef: React.MutableRefObject<boolean>;\n};\n\nexport function useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n scrollLoadLockRef,\n loadMoreLimit = 25,\n}: UseLoadMessagesOptions): UseLoadMessagesReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [hasMore, setHasMore] = useState(true);\n const [hasNewer, setHasNewer] = useState(false);\n const [shiftMode, setShiftMode] = useState(false);\n\n // Reset shiftMode on channel switch so initial load isn't treated as a prepend\n useEffect(() => {\n setShiftMode(false);\n }, [activeChannel?.cid]);\n\n // Reset shiftMode to false after the prepend render is committed.\n // shift should only be true for the single render cycle when older messages\n // are prepended; leaving it on causes virtua to mis-compensate scroll\n // positions when new messages are appended at the bottom, which leads\n // to intermittent message overlapping.\n useEffect(() => {\n if (shiftMode) {\n setShiftMode(false);\n }\n }, [shiftMode]);\n\n // Refs synced from state (avoid handleScroll recreation on state change)\n const hasMoreRef = useRef(true);\n hasMoreRef.current = hasMore;\n const hasNewerRef = useRef(false);\n hasNewerRef.current = hasNewer;\n const isAtBottomRef = useRef(true);\n\n // Concurrency guards\n const loadingMoreRef = useRef(false);\n const loadingNewerRef = useRef(false);\n\n const loadMore = useCallback(async () => {\n if (!activeChannel || loadingMoreRef.current) return;\n\n const currentMessages = messagesRef.current;\n const oldestMessage = currentMessages[0];\n if (!oldestMessage?.id) return;\n\n loadingMoreRef.current = true;\n try {\n const olderRaw = await activeChannel.queryMessagesLessThanId(oldestMessage.id, loadMoreLimit);\n\n if (olderRaw.length === 0) {\n setHasMore(false);\n return;\n }\n\n const olderFormatted = olderRaw.map((msg: any) => formatMessage(msg));\n setShiftMode(true);\n setMessages((prev) => {\n const unique = dedupMessages(olderFormatted, prev);\n if (unique.length === 0) {\n setHasMore(false);\n }\n return [...unique, ...prev];\n });\n } catch (err) {\n console.error('Failed to load more messages:', err);\n } finally {\n loadingMoreRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const loadNewer = useCallback(async () => {\n if (!activeChannel || loadingNewerRef.current) return;\n\n const currentMessages = messagesRef.current;\n const newestMessage = currentMessages[currentMessages.length - 1];\n if (!newestMessage?.id) return;\n\n loadingNewerRef.current = true;\n try {\n const newerRaw = await activeChannel.queryMessagesGreaterThanId(newestMessage.id, loadMoreLimit);\n\n if (newerRaw.length === 0) {\n setHasNewer(false);\n return;\n }\n\n const newerFormatted = newerRaw.map((msg: any) => formatMessage(msg));\n setMessages((prev) => {\n const unique = dedupMessages(newerFormatted, prev);\n if (unique.length === 0) {\n setHasNewer(false);\n }\n return [...prev, ...unique];\n });\n } catch (err) {\n console.error('Failed to load newer messages:', err);\n } finally {\n loadingNewerRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const handleScroll = useCallback(\n (offset: number) => {\n if (jumpingRef.current || scrollLoadLockRef?.current) return;\n const handle = vlistRef.current;\n if (!handle) return;\n const { scrollSize, viewportSize } = handle;\n\n const isBottom = Math.ceil(offset + viewportSize) >= scrollSize - 20;\n isAtBottomRef.current = isBottom;\n\n // Skip if content doesn't fill the viewport\n if (scrollSize <= viewportSize) {\n isAtBottomRef.current = true;\n return;\n }\n\n if (offset <= LOAD_MORE_THRESHOLD && hasMoreRef.current) {\n loadMore();\n }\n\n if (offset + viewportSize >= scrollSize - LOAD_MORE_THRESHOLD && hasNewerRef.current) {\n loadNewer();\n }\n },\n [loadMore, loadNewer, scrollLoadLockRef],\n );\n\n return {\n shiftMode,\n hasMore,\n setHasMore,\n hasNewer,\n setHasNewer,\n hasMoreRef,\n hasNewerRef,\n loadingMoreRef,\n loadingNewerRef,\n loadMore,\n loadNewer,\n handleScroll,\n isAtBottomRef,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { dedupMessages } from './useLoadMessages';\nimport { useChatClient } from './useChatClient';\nimport { getDateKey } from '../utils';\n\nexport type UseScrollToMessageOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n /** Getter to access the VList DOM element (scoped to container) */\n getVListElement: () => HTMLElement | null;\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during jumps */\n jumpingRef: React.MutableRefObject<boolean>;\n};\n\nexport type UseScrollToMessageReturn = {\n highlightedId: string | null;\n scrollToMessage: (messageId: string) => void;\n jumpToLatest: () => void;\n};\n\nfunction getRenderedMessageIndex(messages: FormatMessageResponse[], messageId: string): number {\n let renderedIndex = 0;\n\n for (let i = 0; i < messages.length; i += 1) {\n const message = messages[i];\n const prevMessage = i > 0 ? messages[i - 1] : null;\n const showDateSeparator =\n !prevMessage || getDateKey(message.created_at) !== getDateKey(prevMessage.created_at);\n\n if (showDateSeparator) renderedIndex += 1;\n if (message.id === messageId) return renderedIndex;\n renderedIndex += 1;\n }\n\n return -1;\n}\n\nexport function useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n}: UseScrollToMessageOptions): UseScrollToMessageReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [highlightedId, setHighlightedId] = useState<string | null>(null);\n const highlightTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Cleanup highlight timer on unmount\n useEffect(() => {\n return () => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n };\n }, []);\n\n const highlight = useCallback((messageId: string) => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n setHighlightedId(messageId);\n highlightTimerRef.current = setTimeout(() => {\n setHighlightedId(null);\n highlightTimerRef.current = null;\n }, 2500);\n }, []);\n\n const scrollToMessage = useCallback(\n async (messageId: string) => {\n // Prevent concurrent calls\n if (jumpingRef.current) return;\n\n // Case 1: message is already in current list\n const idx = messagesRef.current.findIndex((m) => m.id === messageId);\n if (idx !== -1) {\n const renderedIdx = getRenderedMessageIndex(messagesRef.current, messageId);\n if (renderedIdx !== -1) {\n jumpingRef.current = true;\n vlistRef.current?.scrollToIndex(renderedIdx, { align: 'center', smooth: true });\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }\n highlight(messageId);\n return;\n }\n\n // Case 2: message NOT in list — fetch around it\n if (!activeChannel) return;\n\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n try {\n const rawMessages = await activeChannel.queryMessagesAroundId(messageId, 25);\n if (!rawMessages || rawMessages.length === 0) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n const formatted = rawMessages.map((msg: any) => formatMessage(msg));\n const unique = dedupMessages(formatted);\n\n setHasMore(true);\n setHasNewer(true);\n setMessages(unique);\n\n // Wait for VList to render, then jump while hidden, then fade in\n setTimeout(() => {\n const renderedIdx = getRenderedMessageIndex(unique, messageId);\n if (renderedIdx === -1) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n vlistRef.current?.scrollToIndex(renderedIdx, { align: 'center' });\n\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n highlight(messageId);\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n } catch (err) {\n console.error('Failed to fetch messages around ID:', err);\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n }\n },\n [activeChannel, highlight, setMessages, setHasMore, setHasNewer, getVListElement],\n );\n\n const jumpToLatest = useCallback(() => {\n if (!activeChannel) return;\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n const latestMsgs = [...activeChannel.state.latestMessages];\n setMessages(latestMsgs);\n setHasNewer(false);\n setHasMore(true);\n\n setTimeout(() => {\n scrollToBottom(false);\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n }, [activeChannel, scrollToBottom, getVListElement, setMessages, setHasMore, setHasNewer]);\n\n return { highlightedId, scrollToMessage, jumpToLatest };\n}\n","import { useEffect, useCallback, useRef, useLayoutEffect } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isPendingMember } from '../channelRoleUtils';\n\nexport type UseChannelMessagesOptions = {\n scrollToBottom: (smooth: boolean) => void;\n /** Reads the live virtual-list metrics to decide whether the viewport is near the bottom. */\n isNearBottom?: () => boolean;\n /** Temporarily blocks scroll-triggered pagination while auto-following new messages. */\n holdScrollLoadLock?: (duration?: number) => void;\n /** Shared guard ref — blocks scroll-triggered loads during channel switch */\n jumpingRef: React.MutableRefObject<boolean>;\n isAtBottomRef: React.MutableRefObject<boolean>;\n /** Called to reset load-more state when channel switches */\n onChannelSwitch?: () => void;\n /** Whether to include hidden (deleted) messages in the initial channel query */\n includeHiddenMessages?: boolean;\n /** Ref to the message list container for smooth opacity transitions */\n containerRef?: React.RefObject<HTMLDivElement>;\n};\n\n// Track channels that have already been queried with include_hidden_messages globally for the session\nconst fullyQueriedChannels = new Set<string>();\nexport const markChannelAsFullyQueried = (cid: string) => fullyQueriedChannels.add(cid);\n\nconst isInactiveInviteRole = (role?: string) => isPendingMember(role) || role === 'rejected' || role === 'skipped';\nconst isE2eeChannel = (channel: any, client: any) => {\n if (channel?.data?.mls_enabled === true) return true;\n const parentCid = channel?.data?.parent_cid as string | undefined;\n if (!parentCid) return false;\n return client?.activeChannels?.[parentCid]?.data?.mls_enabled === true;\n};\n\n/**\n * Schedule multiple scroll-to-bottom attempts with increasing delays.\n * Handles content that changes height after initial render (images, embeds).\n */\nconst SCROLL_DELAYS = [50, 200, 500, 1000];\n\n/**\n * Subscribes to channel message events and handles:\n * - message.new → sync + scroll to bottom\n * - message.updated / message.deleted → sync only\n * - Channel switch → reset state + scroll to bottom\n */\nexport function useChannelMessages({\n scrollToBottom,\n isNearBottom,\n holdScrollLoadLock,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch,\n includeHiddenMessages = true,\n containerRef,\n}: UseChannelMessagesOptions): void {\n const { client, activeChannel, syncMessages, setMessages, setReadState } = useChatClient();\n const inviteRefreshInFlightRef = useRef<Set<string>>(new Set());\n\n const shouldAutoScroll = useCallback(\n () => isAtBottomRef.current || Boolean(isNearBottom?.()),\n [isAtBottomRef, isNearBottom],\n );\n\n const snapToBottomAfterCommit = useCallback(\n (force = false) => {\n if (force) {\n isAtBottomRef.current = true;\n }\n if (force || shouldAutoScroll()) {\n holdScrollLoadLock?.(750);\n }\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (force || shouldAutoScroll()) {\n scrollToBottom(false);\n }\n });\n });\n\n [80, 180, 360].forEach((delay) => {\n setTimeout(() => {\n if (force || shouldAutoScroll()) {\n scrollToBottom(false);\n }\n }, delay);\n });\n },\n [scrollToBottom, shouldAutoScroll, isAtBottomRef, holdScrollLoadLock],\n );\n\n const scheduleScrollToBottom = useCallback(\n (smooth: boolean, force = false) => {\n if (force) {\n isAtBottomRef.current = true;\n }\n if (smooth) {\n // Trigger smooth scroll exactly once, otherwise browsers will\n // cancel the smooth animation if called multiple times in a row\n setTimeout(() => {\n if (!force && !shouldAutoScroll()) return;\n scrollToBottom(true);\n }, 100);\n } else {\n SCROLL_DELAYS.forEach((delay) => {\n setTimeout(() => {\n if (!force && !shouldAutoScroll()) return;\n scrollToBottom(false);\n }, delay);\n });\n }\n },\n [scrollToBottom, isAtBottomRef, shouldAutoScroll],\n );\n\n // Block scroll-triggered loadMore SYNCHRONOUSLY before browser paint.\n // VList remounts (key change) and fires onScroll during layout — useEffect\n // runs too late to block it. useLayoutEffect runs before paint/scroll events.\n useLayoutEffect(() => {\n if (!activeChannel) return;\n jumpingRef.current = true;\n isAtBottomRef.current = true;\n }, [activeChannel]);\n\n useEffect(() => {\n if (!activeChannel) return;\n\n // Reset state for the new channel\n onChannelSwitch?.();\n\n // Instantly hide the list when channel changes\n const el = containerRef?.current;\n if (el) {\n el.style.opacity = '0';\n el.style.transition = 'none';\n }\n\n const fadeListIn = () => {\n if (!el) return;\n // Allow virtua a brief moment to measure items after scroll before showing\n setTimeout(() => {\n el.style.transition = 'opacity 0.1s ease-out';\n el.style.opacity = '1';\n }, 50);\n };\n\n const isDecryptedPlaintextMessage = (message: any) => {\n if (!message || message.e2ee_status === 'failed' || message.e2ee_status === 'decrypting') return false;\n return (\n typeof message.text === 'string' ||\n Boolean(message.attachments?.length) ||\n Boolean(message.sticker_url) ||\n Boolean(message.poll_type) ||\n Boolean(message.poll_choice_counts) ||\n Boolean(message.latest_poll_choices)\n );\n };\n\n const normalizeDecryptedMessage = (message: any) => {\n if (!isDecryptedPlaintextMessage(message)) return message;\n return {\n ...message,\n content_type: 'standard',\n type: message.sticker_url ? 'sticker' : message.type,\n };\n };\n\n const getMessageAndQuoteIds = (messages: any[]) =>\n Array.from(\n new Set(\n messages.flatMap((message: any) =>\n [message?.id, message?.quoted_message_id].filter(\n (id): id is string => typeof id === 'string' && id.length > 0,\n ),\n ),\n ),\n );\n\n const loadStoredE2eeMessagesById = async (messageIds: string[]) => {\n const storage = client.encryptionManager?.storage;\n if (!storage || messageIds.length === 0) return [];\n\n const uniqueIds = Array.from(new Set(messageIds));\n if (storage.loadE2eeMessages) {\n const stored = await storage.loadE2eeMessages(uniqueIds);\n return Array.from(stored.values());\n }\n\n const stored = await Promise.all(uniqueIds.map((id) => storage.loadE2eeMessage(id).catch(() => null)));\n return stored.filter(Boolean);\n };\n\n const mergeAndFilterE2eeMessages = (\n baseMessages: any[],\n decryptedMessages: any[],\n options: { includeMissing?: boolean } = {},\n ) => {\n const includeMissing = options.includeMissing ?? true;\n const byId = new Map(baseMessages.map((msg: any) => [msg.id, msg]));\n for (const decrypted of decryptedMessages) {\n const normalized = normalizeDecryptedMessage(decrypted);\n const hasPlaintext = isDecryptedPlaintextMessage(normalized);\n const current: any = byId.get(decrypted.id);\n if (!includeMissing && !current) continue;\n byId.set(decrypted.id, {\n ...(current || {}),\n ...normalized,\n content_type: hasPlaintext\n ? normalized.content_type || current?.content_type || 'standard'\n : normalized.content_type || current?.content_type,\n status: normalized.status ?? (hasPlaintext ? 'received' : current?.status ?? null),\n });\n }\n\n return Array.from(byId.values()).sort((a: any, b: any) => {\n const aTime = new Date(a.created_at || 0).getTime();\n const bTime = new Date(b.created_at || 0).getTime();\n return aTime - bTime;\n });\n };\n\n const mergeDecryptedMessages = (decryptedMessages: any[], includeMissing = false) => {\n if (!decryptedMessages.length) {\n setMessages((prev) => mergeAndFilterE2eeMessages(prev, []));\n return;\n }\n setMessages((prev) =>\n mergeAndFilterE2eeMessages(prev, decryptedMessages, { includeMissing: includeMissing || prev.length === 0 }),\n );\n };\n\n const syncMessagesWithE2eeCache = (options: { includeStoredWindow?: boolean } = {}) => {\n if (!isE2eeChannel(activeChannel, client) || !client.encryptionManager?.storage || !activeChannel.cid) {\n syncMessages();\n return;\n }\n\n const baseMessages = [...activeChannel.state.latestMessages];\n setMessages(mergeAndFilterE2eeMessages(baseMessages, []));\n\n const loadStoredMessages = options.includeStoredWindow\n ? client.encryptionManager.storage.getE2eeMessages(activeChannel.cid, 100)\n : loadStoredE2eeMessagesById(getMessageAndQuoteIds(baseMessages));\n\n loadStoredMessages\n .then((decryptedMessages: any[]) => {\n setMessages((prev) =>\n mergeAndFilterE2eeMessages(prev.length ? prev : baseMessages, decryptedMessages, {\n includeMissing: options.includeStoredWindow === true,\n }),\n );\n })\n .catch((err: any) => console.warn('[E2EE] Failed to load decrypted message cache', err));\n };\n\n const syncStoredE2eeMessages = (includeStoredWindow = false) => {\n if (!isE2eeChannel(activeChannel, client) || !client.encryptionManager?.storage || !activeChannel.cid) return;\n const baseMessages = [...activeChannel.state.latestMessages];\n const loadStoredMessages = includeStoredWindow\n ? client.encryptionManager.storage.getE2eeMessages(activeChannel.cid, 100)\n : loadStoredE2eeMessagesById(getMessageAndQuoteIds(baseMessages));\n\n loadStoredMessages\n .then((storedMessages: any[]) => mergeDecryptedMessages(storedMessages, includeStoredWindow))\n .catch((err: any) => console.warn('[E2EE] Failed to load decrypted message cache', err));\n };\n\n const ensureE2eeChannelReady = () => {\n if (!isE2eeChannel(activeChannel, client) || !client.encryptionManager?.initialized || !activeChannel.cid) return;\n if (isInactiveInviteRole(activeChannel.state?.membership?.channel_role as string)) return;\n client.encryptionManager\n .ensureChannelReady(activeChannel.type, activeChannel.id, activeChannel.cid, { source: 'open' })\n .then(() => syncMessagesWithE2eeCache({ includeStoredWindow: true }))\n .catch((err: any) => console.warn('[E2EE] Failed to ensure channel ready', err));\n };\n\n // Fetch hidden messages if not already done for this channel\n const cid = activeChannel.cid;\n if (includeHiddenMessages && cid && !fullyQueriedChannels.has(cid)) {\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n activeChannel\n .query({\n messages: { limit: 25, include_hidden_messages: true },\n })\n .then(() => {\n fullyQueriedChannels.add(cid);\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n ensureE2eeChannelReady();\n // Sync initial read state from SDK so read receipts show immediately\n setReadState({ ...activeChannel.state.read });\n scheduleScrollToBottom(false);\n fadeListIn(); // Fade in AFTER query finishes and sync is called\n // Release jumping guard AFTER scrollToBottom has had time to execute.\n // syncMessages() triggers a VList re-render which fires onScroll at\n // offset≈0, and scheduleScrollToBottom's first scroll is at +50ms.\n // If we release jumpingRef synchronously, loadMore fires before the\n // scroll. Delay to 150ms so the +50ms scroll runs first.\n setTimeout(() => {\n jumpingRef.current = false;\n }, 150);\n })\n .catch((err: any) => {\n console.error('Failed to query channel on select', err);\n fadeListIn(); // Fade in anyway on error\n setTimeout(() => {\n jumpingRef.current = false;\n }, 100);\n });\n } else {\n // Already queried: sync cache immediately for instant UI, scroll and fade in quickly\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n ensureE2eeChannelReady();\n // Sync initial read state from SDK so read receipts show immediately\n setReadState({ ...activeChannel.state.read });\n setTimeout(() => {\n scheduleScrollToBottom(false);\n fadeListIn();\n }, 0);\n // Release after a short delay so scrollToBottom's scroll event doesn't\n // trigger loadMore\n setTimeout(() => {\n jumpingRef.current = false;\n }, 100);\n\n // Background re-query to ensure messages are fresh (e.g. after scrollToMessage\n // replaced messages with a small window, or after a stale reconnect).\n // This does NOT block the UI — cached messages are already visible.\n activeChannel\n .query({ messages: { limit: 25, include_hidden_messages: includeHiddenMessages } })\n .then(() => {\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n setReadState({ ...activeChannel.state.read });\n })\n .catch((err: any) => {\n console.warn('Background re-query for channel messages failed', err);\n });\n }\n\n const handleNewMessage = (event: Event) => {\n // Capture scroll state BEFORE sync causes re-render\n const wasAtBottom = shouldAutoScroll();\n const isOwnMessage = event.message?.user?.id === client.userID || event.message?.user_id === client.userID;\n const shouldFollowBottom = isOwnMessage || wasAtBottom;\n if (shouldFollowBottom) {\n isAtBottomRef.current = true;\n holdScrollLoadLock?.(750);\n }\n\n syncMessagesWithE2eeCache();\n\n if (isOwnMessage) {\n // Own/realtime-at-bottom messages use INSTANT scroll to avoid\n // animation overlap jank during rapid typing. Multiple smooth scrolls\n // in quick succession cause the visible \"jump/snap\" effect because\n // each new animation cancels the previous one mid-way.\n snapToBottomAfterCommit(true);\n } else if (wasAtBottom) {\n snapToBottomAfterCommit(true);\n }\n };\n\n const handleMessageChange = (event: Event) => {\n syncMessagesWithE2eeCache();\n };\n\n const handleMessageRead = (_event: Event) => {\n // SDK already updated channel.state.read — sync into React state\n setReadState({ ...activeChannel.state.read });\n // Read receipt avatars appear below the last message, increasing content\n // height. Auto-scroll so the user doesn't have to manually scroll down\n // to see the \"seen\" indicator.\n if (shouldAutoScroll()) {\n setTimeout(() => {\n if (shouldAutoScroll()) {\n scrollToBottom(false);\n }\n }, 100);\n }\n };\n\n const handleUnblocked = (event: Event) => {\n // If the current user's block status was updated (meaning we unblocked someone)\n if (event.member?.user_id === client.userID) {\n // Refetch latest messages to fill in any missed during the block period\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n scheduleScrollToBottom(false);\n const isPending = isPendingMember(activeChannel.state?.membership?.channel_role as string);\n if (!isPending) {\n activeChannel.markRead().catch(() => {});\n }\n })\n .catch((e: any) => console.error('Failed to sync messages after unblock', e));\n }\n };\n\n const refreshAfterOwnInviteMembership = (event: Event) => {\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as any).channel_id ? `${(event as any).channel_type}:${(event as any).channel_id}` : undefined);\n if (eventCid !== activeChannel.cid) return;\n\n const memberUserId = (event as any).member?.user_id;\n if (memberUserId && memberUserId !== client.userID) return;\n if (inviteRefreshInFlightRef.current.has(eventCid)) return;\n\n inviteRefreshInFlightRef.current.add(eventCid);\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n scheduleScrollToBottom(false);\n activeChannel.markRead().catch(() => {});\n })\n .catch((e: any) => console.error('Failed to refresh channel after invite membership update', e))\n .finally(() => {\n inviteRefreshInFlightRef.current.delete(eventCid);\n });\n };\n\n const handleRecovery = () => {\n // recoverState() only fetches channels with message_limit: 1 (for sidebar previews).\n // Re-query the active channel with a proper limit to load all missed messages.\n activeChannel\n .query({ messages: { limit: 25, include_hidden_messages: true } })\n .then(() => {\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n ensureE2eeChannelReady();\n setReadState({ ...activeChannel.state.read });\n scheduleScrollToBottom(false);\n })\n .catch((err: any) => {\n console.error('Failed to recover channel messages after reconnect', err);\n // Fallback: sync whatever we have from recoverState\n syncMessagesWithE2eeCache({ includeStoredWindow: true });\n ensureE2eeChannelReady();\n scheduleScrollToBottom(false);\n });\n };\n\n const handleE2eeDecrypted = (event: any) => {\n if (!event?.message?.id || event.cid !== activeChannel.cid) return;\n const wasAtBottom = shouldAutoScroll();\n mergeDecryptedMessages([event.message]);\n if (wasAtBottom) {\n snapToBottomAfterCommit(true);\n }\n };\n\n const handleE2eeRefresh = (event: any) => {\n if (event?.cid === activeChannel.cid) {\n if (Array.isArray(event.messages) && event.messages.length > 0) {\n mergeDecryptedMessages(event.messages);\n }\n syncStoredE2eeMessages();\n }\n };\n\n const eventClient = activeChannel.getClient();\n const sub1 = activeChannel.on('message.new', handleNewMessage);\n const sub2 = activeChannel.on('message.updated', handleMessageChange);\n const sub3 = activeChannel.on('message.deleted', handleMessageChange);\n const sub4 = activeChannel.on('message.pinned', handleMessageChange);\n const sub5 = activeChannel.on('message.unpinned', handleMessageChange);\n const sub6 = activeChannel.on('message.read', handleMessageRead);\n const sub7 = activeChannel.on('message.deleted_for_me', handleMessageChange);\n const sub8 = activeChannel.on('reaction.new', handleMessageChange);\n const sub9 = activeChannel.on('reaction.deleted', handleMessageChange);\n const sub10 = activeChannel.on('member.unblocked', handleUnblocked);\n const sub11 = activeChannel.on('channel.truncate', handleMessageChange);\n const sub12 = activeChannel.on('channel.truncate_for_me', handleMessageChange);\n\n const sub13 = eventClient.on('notification.invite_accepted', refreshAfterOwnInviteMembership);\n const sub14 = eventClient.on('member.joined', refreshAfterOwnInviteMembership);\n const sub15 = eventClient.on('connection.recovered', handleRecovery);\n const sub16 = eventClient.on('e2ee.message_decrypted' as any, handleE2eeDecrypted);\n const sub17 = eventClient.on('e2ee.post_join_sync' as any, handleE2eeRefresh);\n const sub18 = eventClient.on('e2ee.channel_ready' as any, handleE2eeRefresh);\n const sub19 = eventClient.on('e2ee.local_messages_loaded' as any, handleE2eeRefresh);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n sub15.unsubscribe();\n sub16.unsubscribe();\n sub17.unsubscribe();\n sub18.unsubscribe();\n sub19.unsubscribe();\n };\n }, [activeChannel, client, scrollToBottom, scheduleScrollToBottom, shouldAutoScroll, snapToBottomAfterCommit, syncMessages, setMessages, onChannelSwitch, setReadState, holdScrollLoadLock]);\n}\n","import React from 'react';\nimport type { MessageItemProps, SystemMessageItemProps } from '../types';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { MessageActionsBox } from './MessageActionsBox';\nimport { MessageReactions } from './MessageReactions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { formatTime } from '../utils';\nimport { isSystemMessage, isDeletedDisplayMessage, isStickerMessage, isSignalMessage } from '../messageTypeUtils';\n\nexport type { MessageItemProps, SystemMessageItemProps } from '../types';\n\n/* ----------------------------------------------------------\n MessageItem — single regular/signal message row\n ---------------------------------------------------------- */\n/* Inline status icon for own messages (sent / sending / error) */\nconst InlineStatusIcon: React.FC<{ status?: string; isOwnMessage: boolean; isLastInGroup: boolean }> = React.memo(({\n status,\n isOwnMessage,\n isLastInGroup,\n}) => {\n if (!isOwnMessage) return null;\n\n const isError = status === 'error' || status === 'failed_offline';\n if (!isLastInGroup && !isError) return null;\n\n if (isError) {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--failed\" title=\"Failed to send\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line>\n </svg>\n </span>\n );\n }\n\n if (status === 'sending') {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sending\" title=\"Sending...\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <polyline points=\"12 6 12 12 16 14\"></polyline>\n </svg>\n </span>\n );\n }\n\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sent\" title=\"Sent\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n </span>\n );\n});\nInlineStatusIcon.displayName = 'InlineStatusIcon';\n\nfunction findQuotedMessageInChannelState(channel: any, quotedMessageId?: string) {\n if (!channel || !quotedMessageId) return undefined;\n\n const messageSets = Array.isArray(channel.state?.messageSets) ? channel.state.messageSets : [];\n for (const set of messageSets) {\n const messages = Array.isArray(set?.messages) ? set.messages : [];\n const found = messages.find((item: any) => item?.id === quotedMessageId);\n if (found) return found;\n }\n\n const pinnedMessages = Array.isArray(channel.state?.pinnedMessages) ? channel.state.pinnedMessages : [];\n return pinnedMessages.find((item: any) => item?.id === quotedMessageId);\n}\n\nfunction hasRenderableQuotedMessageContent(quotedMessage: any) {\n if (!quotedMessage) return false;\n if (typeof quotedMessage.text === 'string' && quotedMessage.text.trim()) return true;\n if (Array.isArray(quotedMessage.attachments) && quotedMessage.attachments.length > 0) return true;\n if (typeof quotedMessage.sticker_url === 'string' && quotedMessage.sticker_url) return true;\n if (isStickerMessage(quotedMessage)) return true;\n return false;\n}\n\nexport const MessageItem: React.FC<MessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n isFirstInGroup,\n isLastInGroup,\n isHighlighted,\n AvatarComponent,\n MessageBubble,\n MessageRenderer,\n onClickQuote,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent = MessageActionsBox,\n MessageReactionsComponent = MessageReactions,\n forwardedLabel = 'Forwarded',\n editedLabel = 'Edited',\n deletedMessageLabel = 'This message was deleted',\n attachmentLabel = 'Attachment',\n unavailableMessageLabel = 'Message unavailable',\n stickerLabel = 'Sticker',\n encryptedMessageLabel,\n encryptedMessageFailedLabel,\n encryptedMessageDecryptingLabel,\n systemMessageTranslations,\n signalMessageTranslations,\n onMentionClick,\n onUserNameClick,\n onAddReactionClick,\n hideAvatar,\n}) => {\n const { activeChannel, client } = useChatClient();\n const { hasCapability } = useChannelCapabilities();\n\n const canReact = hasCapability('send-reaction');\n\n const userName = message.user?.name || message.user_id;\n const userAvatar = message.user?.avatar;\n\n const directQuotedMessage = (message as any).quoted_message;\n const stateQuotedMessage = findQuotedMessageInChannelState(activeChannel, (message as any).quoted_message_id);\n const quotedMessage =\n (hasRenderableQuotedMessageContent(directQuotedMessage) ? directQuotedMessage : undefined) ||\n (hasRenderableQuotedMessageContent(stateQuotedMessage) ? stateQuotedMessage : undefined) ||\n directQuotedMessage;\n const isForwarded = !!(message as any).forward_cid;\n const oldTexts = (message as any).old_texts;\n const isEdited = oldTexts && oldTexts.length > 0;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isDeletedDisplay = isDeletedDisplayMessage(message);\n\n const handleReactionToggle = React.useCallback(async (type: string) => {\n if (!activeChannel || !canReact) return;\n const currentUserId = client?.userID;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some((r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n }, [activeChannel, message, client?.userID]);\n\n const statusClass =\n message.status === 'sending'\n ? 'ermis-message--sending'\n : (message.status === 'error' || message.status === 'failed_offline')\n ? 'ermis-message--error'\n : '';\n\n const isNewMessage = React.useMemo(() => {\n if (!message.created_at) return false;\n return Date.now() - new Date(message.created_at).getTime() < 1000;\n }, [message.created_at]);\n\n const isSticker = React.useMemo(() => isStickerMessage(message), [message]);\n\n const itemClass = [\n 'ermis-message-list__item',\n isOwnMessage ? 'ermis-message-list__item--own' : 'ermis-message-list__item--other',\n isFirstInGroup && isLastInGroup ? 'ermis-message-list__item--group-single' : '',\n isFirstInGroup && !isLastInGroup ? 'ermis-message-list__item--group-top' : '',\n !isFirstInGroup && !isLastInGroup ? 'ermis-message-list__item--group-middle' : '',\n !isFirstInGroup && isLastInGroup ? 'ermis-message-list__item--group-bottom' : '',\n isHighlighted ? 'ermis-message-list__item--highlighted' : '',\n isNewMessage ? 'ermis-message-list__item--new' : '',\n isDeletedDisplay ? 'ermis-message-list__item--deleted-display' : '',\n isSticker ? 'ermis-message-list__item--sticker' : '',\n isSignalMessage(message) ? 'ermis-message-list__item--signal' : '',\n statusClass,\n ].filter(Boolean).join(' ');\n\n const contentClass = [\n 'ermis-message-list__item-content',\n hasAttachments && !isDeletedDisplay ? 'ermis-message-list__item-content--has-attachments' : '',\n ].filter(Boolean).join(' ');\n\n // Deleted display: show icon + label, no actions/reactions/quote/attachments\n if (isDeletedDisplay) {\n return (\n <div className={itemClass} data-message-id={message.id}>\n {!hideAvatar && !isOwnMessage && (\n <div className=\"ermis-message-list__item-avatar\">\n {isLastInGroup\n ? <AvatarComponent image={userAvatar} name={userName} size={36} />\n : <div style={{ width: 36 }} />\n }\n </div>\n )}\n <div className={contentClass}>\n {!isOwnMessage && isFirstInGroup && (\n <span className=\"ermis-message-list__item-user\">{userName}</span>\n )}\n <div className=\"ermis-message-list__bubble-wrapper\">\n <MessageBubble message={message} isOwnMessage={isOwnMessage}>\n <span className=\"ermis-message-list__deleted-text\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n {deletedMessageLabel}\n </span>\n <span className=\"ermis-message-list__item-time\">\n {formatTime(message.created_at)}\n </span>\n </MessageBubble>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className={itemClass} data-message-id={message.id}>\n {/* Avatar area: only render when not hidden by group wrapper */}\n {!hideAvatar && !isOwnMessage && (\n <div className=\"ermis-message-list__item-avatar\">\n {isLastInGroup\n ? <AvatarComponent image={userAvatar} name={userName} size={36} />\n : <div style={{ width: 36 }} />\n }\n </div>\n )}\n <div className={contentClass}>\n {!isOwnMessage && isFirstInGroup && (\n <span\n className={`ermis-message-list__item-user${onUserNameClick ? ' ermis-message-list__item-user--clickable' : ''}`}\n onClick={onUserNameClick ? (e) => { e.stopPropagation(); const uid = message.user?.id || message.user_id; if (uid) onUserNameClick(uid); } : undefined}\n >{userName}</span>\n )}\n {/* Quoted message preview */}\n {quotedMessage && onClickQuote && (\n <QuotedMessagePreviewComponent\n quotedMessage={quotedMessage}\n isOwnMessage={isOwnMessage}\n onClick={onClickQuote}\n attachmentLabel={attachmentLabel}\n unavailableMessageLabel={unavailableMessageLabel}\n stickerLabel={stickerLabel}\n deletedMessageLabel={typeof deletedMessageLabel === 'string' ? deletedMessageLabel : 'This message was deleted'}\n />\n )}\n <div className=\"ermis-message-list__bubble-wrapper\">\n <MessageBubble message={message} isOwnMessage={isOwnMessage}>\n {isForwarded && (\n <span className=\"ermis-message-list__forwarded-indicator\">{forwardedLabel}</span>\n )}\n <MessageRenderer\n message={message}\n isOwnMessage={isOwnMessage}\n systemMessageTranslations={systemMessageTranslations}\n signalMessageTranslations={signalMessageTranslations}\n onMentionClick={onMentionClick}\n encryptedMessageLabel={encryptedMessageLabel}\n encryptedMessageFailedLabel={encryptedMessageFailedLabel}\n encryptedMessageDecryptingLabel={encryptedMessageDecryptingLabel}\n />\n\n {/* Message Reactions — inside bubble */}\n {MessageReactionsComponent && (\n <>\n <div className=\"ermis-message-reactions-break\" style={{ width: '100%', display: 'block' }}></div>\n <MessageReactionsComponent\n reactionCounts={(message as any).reaction_counts}\n ownReactions={(message as any).own_reactions}\n latestReactions={(message as any).latest_reactions}\n onClickReaction={handleReactionToggle}\n disabled={!canReact}\n isOwnMessage={isOwnMessage}\n />\n </>\n )}\n\n {/* Time rendered AFTER text/reactions for bottom-right alignment */}\n {!isSignalMessage(message) && (isLastInGroup || isEdited || message.status === 'error' || message.status === 'failed_offline') && (\n <span className=\"ermis-message-list__item-time\">\n {isEdited && (\n <span\n className=\"ermis-message-list__edited-indicator\"\n // data-tooltip={oldTexts.map((ot: any) => `[${formatTime(ot.created_at)}] ${ot.text}`).join('\\n')}\n >\n {editedLabel}\n </span>\n )}\n {isLastInGroup && formatTime(message.created_at)}\n <InlineStatusIcon status={message.status} isOwnMessage={isOwnMessage} isLastInGroup={isLastInGroup} />\n </span>\n )}\n\n {/* Actions: hover buttons + dropdown menu */}\n {!isSystemMessage(message) && (\n <MessageActionsBoxComponent\n message={message}\n isOwnMessage={isOwnMessage}\n />\n )}\n </MessageBubble>\n </div>\n </div>\n </div>\n );\n});\nMessageItem.displayName = 'MessageItem';\n\n/* ----------------------------------------------------------\n SystemMessageItem — system/notification message row\n ---------------------------------------------------------- */\nexport const SystemMessageItem: React.FC<SystemMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n SystemRenderer,\n systemMessageTranslations,\n}) => (\n <div className=\"ermis-message-list__system\">\n <SystemRenderer\n message={message}\n isOwnMessage={isOwnMessage}\n systemMessageTranslations={systemMessageTranslations}\n />\n </div>\n));\nSystemMessageItem.displayName = 'SystemMessageItem';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { QuotedMessagePreviewProps } from '../types';\nimport {\n isImageAttachment,\n isLinkPreviewAttachment,\n isStickerMessage,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n} from '../messageTypeUtils';\nimport { isDeletedDisplayMessage } from '../messageTypeUtils';\n\nexport type { QuotedMessagePreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 100;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\nfunction getAttachmentPreview(\n attachments: NonNullable<QuotedMessagePreviewProps['quotedMessage']['attachments']>,\n attachmentLabel: string,\n): string {\n const firstAttachment = attachments[0];\n if (!firstAttachment) return attachmentLabel;\n\n if (isLinkPreviewAttachment(firstAttachment) && firstAttachment.title) {\n return firstAttachment.title;\n }\n\n if (firstAttachment.title || firstAttachment.file_name) {\n return firstAttachment.title || firstAttachment.file_name || attachmentLabel;\n }\n\n if (isImageAttachment(firstAttachment)) return attachmentLabel;\n if (isVideoAttachment(firstAttachment)) return attachmentLabel;\n if (isVoiceRecordingAttachment(firstAttachment)) return attachmentLabel;\n\n return attachmentLabel;\n}\n\nfunction hasUnavailableContent(quotedMessage: QuotedMessagePreviewProps['quotedMessage']): boolean {\n const hasText = Boolean(quotedMessage.text?.trim());\n if (hasText) return false;\n if (isStickerMessage(quotedMessage)) return false;\n if (quotedMessage.attachments?.length) return false;\n\n return (\n quotedMessage.content_type === 'mls' ||\n Boolean(quotedMessage.mls_ciphertext) ||\n quotedMessage.e2ee_status === 'failed' ||\n quotedMessage.e2ee_status === 'decrypting'\n );\n}\n\nexport const QuotedMessagePreview: React.FC<QuotedMessagePreviewProps> = React.memo(({\n quotedMessage,\n isOwnMessage,\n onClick,\n attachmentLabel = 'Attachment',\n unavailableMessageLabel = 'Message unavailable',\n stickerLabel = 'Sticker',\n deletedMessageLabel = 'This message was deleted',\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const authorName = quotedMessage.user?.name || quotedMessage.user?.id || 'Unknown';\n \n const rawText = quotedMessage.text?.trim() || '';\n const formattedText = useMemo(\n () => replaceMentionsForPreview(rawText, quotedMessage, userMap),\n [rawText, quotedMessage, userMap],\n );\n\n const preview = useMemo(() => {\n if (formattedText) {\n return {\n text: truncateText(formattedText, MAX_PREVIEW_LENGTH),\n unavailable: false,\n };\n }\n\n if (isStickerMessage(quotedMessage)) {\n return {\n text: stickerLabel,\n unavailable: false,\n };\n }\n\n if (quotedMessage.attachments?.length) {\n return {\n text: getAttachmentPreview(quotedMessage.attachments, attachmentLabel),\n unavailable: false,\n };\n }\n\n if (isDeletedDisplayMessage(quotedMessage)) {\n return {\n text: deletedMessageLabel,\n unavailable: true,\n };\n }\n\n if (hasUnavailableContent(quotedMessage)) {\n return {\n text: unavailableMessageLabel,\n unavailable: true,\n };\n }\n\n return {\n text: unavailableMessageLabel,\n unavailable: true,\n };\n }, [attachmentLabel, formattedText, quotedMessage, stickerLabel, unavailableMessageLabel, deletedMessageLabel]);\n\n const handleClick = () => {\n onClick(quotedMessage.id);\n };\n\n return (\n <div\n className={`ermis-quoted-message ${isOwnMessage ? 'ermis-quoted-message--own' : ''}${\n preview.unavailable ? ' ermis-quoted-message--unavailable' : ''\n }`}\n onClick={handleClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleClick();\n }}\n >\n <span className=\"ermis-quoted-message__author\">{authorName}</span>\n <span className=\"ermis-quoted-message__text\">{preview.text}</span>\n </div>\n );\n});\n\nQuotedMessagePreview.displayName = 'QuotedMessagePreview';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useMessageActions } from '../hooks/useMessageActions';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { MessageActionsBoxProps } from '../types';\nimport { Dropdown as DefaultDropdown, closeAllDropdowns } from './Dropdown';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport { MessageQuickReactions } from './MessageQuickReactions';\n\n// Aliased for backward compatibility\nexport const closeAllActionBoxes = closeAllDropdowns;\n\nexport const MessageActionsBox: React.FC<MessageActionsBoxProps> = ({\n message,\n isOwnMessage,\n onReply: onReplyProp,\n onForward,\n onPinToggle,\n onEdit,\n onCopy,\n onDelete,\n onDeleteForMe,\n pinLabel = 'Pin',\n unpinLabel = 'Unpin',\n editLabel = 'Edit',\n copyLabel = 'Copy',\n deleteForMeLabel = 'Delete for me',\n deleteForEveryoneLabel = 'Delete for everyone',\n}) => {\n const { setQuotedMessage, setEditingMessage, setForwardingMessage, activeChannel } = useChatClient();\n const { DropdownComponent } = useChatComponents();\n const Dropdown = DropdownComponent || DefaultDropdown;\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null);\n const actions = useMessageActions(message, isOwnMessage);\n\n // Default handlers\n const onReply = onReplyProp ?? ((msg: FormatMessageResponse) => setQuotedMessage(msg));\n const onForwardHandler = onForward ?? ((msg: FormatMessageResponse) => setForwardingMessage(msg));\n const onPinToggleHandler = onPinToggle ?? (async (msg: FormatMessageResponse, isPinned: boolean) => {\n if (!activeChannel) return;\n try {\n if (isPinned) {\n await activeChannel.unpinMessage(msg.id!);\n } else {\n await activeChannel.pinMessage(msg.id!);\n }\n } catch (err) {\n console.error('Failed to toggle pin', err);\n }\n });\n const onEditHandler = onEdit ?? ((msg: FormatMessageResponse) => setEditingMessage(msg));\n\n const onDeleteForEveryoneHandler = onDelete ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessage(msg.id!);\n } catch (err) {\n console.error('Failed to delete message', err);\n }\n });\n\n const onDeleteForMeHandler = onDeleteForMe ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessageForMe(msg.id!);\n } catch (err) {\n console.error('Failed to delete message for me', err);\n }\n });\n\n const isOpen = anchorRect !== null;\n const onClose = useCallback(() => setAnchorRect(null), []);\n\n const handleMoreClick = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setAnchorRect(rect);\n };\n\n const handleCopy = async () => {\n if (onCopy) {\n onCopy(message);\n } else if (message.text) {\n try {\n await navigator.clipboard.writeText(message.text);\n } catch (err) {\n console.error('Failed to copy text:', err);\n }\n }\n onClose();\n };\n\n return (\n <>\n <div className={`ermis-message-list__actions ${isOpen ? 'ermis-message-list__actions--active' : ''}`}>\n {actions.canReply && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onReply?.(message)} \n title=\"Reply\"\n disabled={!actions.hasCapReply}\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M11.192 15.757c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L9.373 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.955 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53zm10.455 0c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L19.828 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.954 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53z\" />\n </svg>\n </button>\n )}\n <MessageQuickReactions message={message} isOwnMessage={isOwnMessage} disabled={!actions.hasCapReact} />\n {actions.canForward && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onForwardHandler(message)} \n title=\"Forward\"\n disabled={!actions.hasCapQuote}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 14 20 9 15 4\" />\n <path d=\"M4 20v-7a4 4 0 0 1 4-4h12\" />\n </svg>\n </button>\n )}\n <button\n className={`ermis-message-list__actions-trigger ${isOpen ? 'ermis-message-list__actions-trigger--active' : ''}`}\n onClick={handleMoreClick}\n title=\"More actions\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n </div>\n\n <Dropdown \n isOpen={isOpen} \n anchorRect={anchorRect} \n onClose={onClose} \n align={isOwnMessage ? 'right' : 'left'}\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.canPin && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onPinToggleHandler(message, actions.isPinned); onClose(); }}\n disabled={!actions.hasCapPin}\n >\n {actions.isPinned ? unpinLabel : pinLabel}\n </button>\n )}\n {actions.canEdit && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onEditHandler(message); onClose(); }}\n disabled={!actions.hasCapEdit}\n >\n {editLabel}\n </button>\n )}\n {actions.canCopy && (\n <button className=\"ermis-dropdown__item\" onClick={handleCopy}>\n {copyLabel}\n </button>\n )}\n\n {(actions.canDelete || actions.canDeleteForMe) && <div className=\"ermis-dropdown__divider\" />}\n\n {actions.canDeleteForMe && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForMeHandler(message); onClose(); }}\n disabled={!actions.hasCapDeleteForMe}\n >\n {deleteForMeLabel}\n </button>\n )}\n {actions.canDelete && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForEveryoneHandler(message); onClose(); }}\n disabled={!actions.hasCapDelete}\n >\n {deleteForEveryoneLabel}\n </button>\n )}\n </div>\n </Dropdown>\n </>\n );\n};\n","import { useMemo } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { useChannelCapabilities } from './useChannelCapabilities';\nimport { usePreviewState } from './usePreviewState';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { isSignalMessage, isSystemMessage, isStickerMessage } from '../messageTypeUtils';\n\nexport type MessageActionList = {\n canEdit: boolean;\n canDelete: boolean;\n canDeleteForMe: boolean;\n canReply: boolean;\n canQuote: boolean;\n canForward: boolean;\n canPin: boolean;\n canCopy: boolean;\n isPinned: boolean;\n hasCapEdit: boolean;\n hasCapDelete: boolean;\n hasCapDeleteForMe: boolean;\n hasCapPin: boolean;\n hasCapReply: boolean;\n hasCapQuote: boolean;\n hasCapReact: boolean;\n};\n\nexport const useMessageActions = (message: FormatMessageResponse, isOwnMessage: boolean): MessageActionList => {\n const { activeChannel, client } = useChatClient();\n const { isGroupChannel: isTeam, isOwner, hasCapability } = useChannelCapabilities();\n const { isPreviewMode } = usePreviewState(activeChannel, client?.userID);\n\n // Only depend on the specific message fields we actually read\n const messageType = message.type;\n const isPinnedFlag = message.pinned || !!message.pinned_at;\n\n return useMemo(() => {\n if (!activeChannel) {\n return {\n canEdit: false,\n canDelete: false,\n canDeleteForMe: false,\n canReply: false,\n canQuote: false,\n canForward: false,\n canPin: false,\n canCopy: false,\n isPinned: false,\n hasCapEdit: false,\n hasCapDelete: false,\n hasCapDeleteForMe: false,\n hasCapPin: false,\n hasCapReply: false,\n hasCapQuote: false,\n hasCapReact: false,\n };\n }\n\n const isSystem = isSystemMessage(message);\n const isSignal = isSignalMessage(message);\n const isSticker = isStickerMessage(message);\n const isPinned = isPinnedFlag;\n\n const isDeleted = message.display_type === 'deleted';\n\n const canEdit = !isPreviewMode && !isSystem && !isSignal && !isSticker && isOwnMessage && !isDeleted;\n\n // Delete for everyone:\n // + Team channel: only the owner can perform this action natively.\n // + Messaging channel: only own messages can be deleted\n const canDeleteForEveryoneTeam = isTeam && isOwner;\n const canDeleteForEveryoneMessaging = !isTeam && isOwnMessage;\n\n const canDelete = !isPreviewMode && !isSystem && (canDeleteForEveryoneTeam || canDeleteForEveryoneMessaging) && !isDeleted;\n const canDeleteForMe = !isPreviewMode && !isSystem && !isDeleted;\n const canReply = !isPreviewMode && !isSystem && !isSignal && !isDeleted;\n const canQuote = !isPreviewMode && !isSystem && !isSignal && !isDeleted;\n const canForward = !isPreviewMode && !isSystem && !isSignal && !isDeleted;\n const canPin = !isPreviewMode && !isSystem && !isSignal && !isDeleted;\n const canCopy = !isSystem && !isSignal && Boolean(message.text?.trim()) && !isDeleted; // Allow copy even in preview mode\n\n const hasCapEdit = hasCapability('update-own-message');\n const hasCapDelete = !isTeam || isOwner || (isOwnMessage && hasCapability('delete-own-message'));\n // Apply the delete-own-message capability to the \"delete for me\" action for own messages\n const hasCapDeleteForMe = !isTeam || isOwner || !isOwnMessage || hasCapability('delete-own-message');\n\n const hasCapReply = hasCapability('send-reply');\n const hasCapQuote = hasCapability('quote-message');\n const hasCapPin = hasCapability('pin-message');\n const hasCapReact = hasCapability('send-reaction');\n\n return {\n canEdit,\n canDelete,\n canDeleteForMe,\n canReply,\n canQuote,\n canForward,\n canPin,\n canCopy,\n isPinned,\n hasCapEdit,\n hasCapDelete,\n hasCapDeleteForMe,\n hasCapPin,\n hasCapReply,\n hasCapQuote,\n hasCapReact,\n };\n }, [activeChannel, isTeam, isOwner, hasCapability, messageType, message.text, isPinnedFlag, isOwnMessage, isPreviewMode]); // Use capabilities from hook\n};\n","import React, { useCallback, useState, useRef, useEffect } from 'react';\nimport { EmojiPicker } from 'frimousse';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst EmojiPickerRoot = EmojiPicker.Root as any;\nconst EmojiPickerSearch = EmojiPicker.Search as any;\nconst EmojiPickerViewport = EmojiPicker.Viewport as any;\nconst EmojiPickerLoading = EmojiPicker.Loading as any;\nconst EmojiPickerEmpty = EmojiPicker.Empty as any;\nconst EmojiPickerList = EmojiPicker.List as any;\n\nconst REACTIONS = ['like', 'love', 'haha', 'sad', 'fire'];\n\nconst EMOJI_MAP: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageQuickReactions: React.FC<{\n message: FormatMessageResponse;\n isOwnMessage: boolean;\n disabled?: boolean;\n}> = React.memo(({ message, isOwnMessage, disabled }) => {\n const { activeChannel, client } = useChatClient();\n const currentUserId = client?.userID;\n const [isExpanded, setIsExpanded] = useState(false);\n const [showPicker, setShowPicker] = useState(false);\n const [pickerPosition, setPickerPosition] = useState<'top' | 'bottom'>('top');\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Close when clicking outside\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setIsExpanded(false);\n setShowPicker(false);\n }\n };\n if (isExpanded || showPicker) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [isExpanded, showPicker]);\n\n const handleReactionToggle = useCallback(\n async (type: string) => {\n if (!activeChannel) return;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n },\n [activeChannel, message, currentUserId]\n );\n\n const isOwnReaction = useCallback(\n (type: string) => {\n return (\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n )\n );\n },\n [message, currentUserId]\n );\n\n const handleMoreClick = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n setPickerPosition(rect.top < 388 ? 'bottom' : 'top');\n }\n setShowPicker((prev) => !prev);\n setIsExpanded(false);\n },\n []\n );\n\n return (\n <div \n ref={containerRef} \n className=\"ermis-qr-wrapper\" \n style={{ position: 'relative', display: 'inline-flex' }}\n onMouseLeave={() => {\n if (!showPicker) {\n setIsExpanded(false);\n }\n }}\n >\n {/* Trigger button (looks like other action buttons) */}\n <button \n className={`ermis-message-list__actions-trigger ${isExpanded || showPicker ? 'ermis-message-list__actions-trigger--active' : ''}`}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); if (!disabled) { setIsExpanded(!isExpanded); setShowPicker(false); } }}\n title=\"Add reaction\"\n disabled={disabled}\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\n <line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\" />\n <line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\" />\n </svg>\n </button>\n\n {/* Horizontal Strip */}\n {isExpanded && (\n <div className=\"ermis-qr__strip ermis-qr__strip--horizontal\" onClick={(e) => e.stopPropagation()}>\n {REACTIONS.map((type) => (\n <button\n key={type}\n className={`ermis-qr__emoji ${isOwnReaction(type) ? 'ermis-qr__emoji--active' : ''}`}\n title={type}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); handleReactionToggle(type); setIsExpanded(false); }}\n >\n {EMOJI_MAP[type]}\n </button>\n ))}\n <button\n className=\"ermis-qr__emoji ermis-qr__emoji--more\"\n title=\"More reactions\"\n onClick={handleMoreClick}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"19\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n )}\n\n {/* Full emoji picker */}\n {showPicker && (\n <div\n className={`ermis-qr__picker ermis-qr__picker--${pickerPosition} ${isOwnMessage ? 'ermis-qr__picker--own' : ''}`}\n onClick={(e) => e.stopPropagation()}\n >\n <EmojiPickerRoot\n className=\"isolate flex h-full w-full flex-col bg-white dark:bg-[#1a1828]\"\n locale=\"vi\"\n onEmojiSelect={(emoji: any) => {\n handleReactionToggle(emoji.emoji);\n setShowPicker(false);\n setIsExpanded(false);\n }}\n >\n <EmojiPickerSearch className=\"z-10 mx-3 mt-3 appearance-none rounded-xl bg-zinc-100 px-3 py-2 text-sm dark:bg-zinc-800 dark:text-zinc-100 outline-none focus:ring-2 focus:ring-primary/50\" />\n <EmojiPickerViewport className=\"relative flex-1 outline-hidden mt-2\">\n <EmojiPickerLoading className=\"absolute inset-0 flex items-center justify-center text-zinc-400 text-sm dark:text-zinc-500\">\n Đang tải…\n </EmojiPickerLoading>\n <EmojiPickerEmpty className=\"absolute inset-0 flex items-center justify-center text-zinc-400 text-sm dark:text-zinc-500\">\n Không tìm thấy emoji.\n </EmojiPickerEmpty>\n <EmojiPickerList\n className=\"select-none pb-1.5\"\n components={{\n CategoryHeader: ({ category, ...props }: any) => (\n <div className=\"bg-white/90 px-3 pt-3 pb-1.5 font-semibold text-zinc-500 text-xs dark:bg-[#1a1828]/90 dark:text-zinc-400 backdrop-blur-md\" {...props}>\n {category.label}\n </div>\n ),\n Row: ({ children, ...props }: any) => (\n <div className=\"scroll-my-1.5 px-2 flex justify-between\" {...props}>\n {children as React.ReactNode}\n </div>\n ),\n Emoji: ({ emoji, ...props }: any) => {\n const { formAction, ...safeProps } = props;\n return (\n <button className=\"flex size-9 items-center justify-center rounded-lg text-xl hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors data-[active]:bg-zinc-100 dark:data-[active]:bg-zinc-800\" {...safeProps}>\n {emoji.emoji}\n </button>\n );\n },\n }}\n />\n </EmojiPickerViewport>\n </EmojiPickerRoot>\n </div>\n )}\n </div>\n );\n});\n\nMessageQuickReactions.displayName = 'MessageQuickReactions';\n","import React from 'react';\nimport type { MessageReactionsProps } from '../types';\n\nimport { useChatClient } from '../hooks/useChatClient';\nimport { createPortal } from 'react-dom';\n\nconst defaultReactionEmojiMap: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nconst ReactionTooltip = ({ text, rect }: { text: string; rect: DOMRect }) => {\n if (!text || !rect) return null;\n return createPortal(\n <div style={{\n position: 'fixed',\n top: rect.top - 6,\n left: rect.left + rect.width / 2,\n transform: 'translate(-50%, -100%)',\n backgroundColor: 'rgba(0, 0, 0, 0.75)',\n color: '#fff',\n padding: '4px 8px',\n borderRadius: '6px',\n fontSize: '11px',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n width: 'max-content',\n maxWidth: '200px',\n textAlign: 'center',\n zIndex: 999999,\n pointerEvents: 'none'\n }}>\n {text}\n </div>,\n document.body\n );\n};\n\nexport const MessageReactions: React.FC<MessageReactionsProps> = React.memo(({\n reactionCounts,\n ownReactions,\n latestReactions,\n onClickReaction,\n disabled,\n isOwnMessage,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n const [hoveredTooltip, setHoveredTooltip] = React.useState<{text: string, rect: DOMRect} | null>(null);\n\n React.useEffect(() => {\n if (hoveredTooltip) {\n const handleHide = () => setHoveredTooltip(null);\n window.addEventListener('scroll', handleHide, true);\n window.addEventListener('resize', handleHide);\n return () => {\n window.removeEventListener('scroll', handleHide, true);\n window.removeEventListener('resize', handleHide);\n };\n }\n }, [hoveredTooltip]);\n\n if (!reactionCounts || Object.keys(reactionCounts).length === 0) return null;\n\n return (\n <div className={`ermis-message-reactions${disabled ? ' ermis-message-reactions--disabled' : ''}${isOwnMessage ? ' ermis-message-reactions--own' : ''}`}>\n {Object.entries(reactionCounts).map(([type, count]) => {\n const isOwn = \n ownReactions?.some((r) => r.type === type) ||\n latestReactions?.some((r) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n \n // Find users who reacted with this type for the tooltip\n const rawUserNames = latestReactions\n ?.filter((r) => r.type === type)\n .map((r: any) => r.user?.name || r.user?.id || r.user_id || 'Someone');\n \n const userNames = Array.from(new Set(rawUserNames || []))\n .map((n: any) => typeof n === 'string' ? n.replace(/‎|\\u200E/gi, '').trim() : n)\n .filter(Boolean);\n\n const tooltip = userNames.length > 0 ? userNames.join(', ') : type;\n const emoji = defaultReactionEmojiMap[type] || type;\n\n return (\n <button\n key={type}\n className={`ermis-message-reactions__item ${\n isOwn ? 'ermis-message-reactions__item--active' : ''\n }`}\n onMouseEnter={(e) => {\n setHoveredTooltip({ text: tooltip, rect: e.currentTarget.getBoundingClientRect() });\n }}\n onMouseLeave={() => setHoveredTooltip(null)}\n onClick={() => onClickReaction?.(type)}\n type=\"button\"\n >\n <span className=\"ermis-message-reactions__emoji\">{emoji}</span>\n {count > 1 && <span className=\"ermis-message-reactions__count\">{count}</span>}\n </button>\n );\n })}\n {hoveredTooltip && <ReactionTooltip text={hoveredTooltip.text} rect={hoveredTooltip.rect} />}\n </div>\n );\n});\n\nMessageReactions.displayName = 'MessageReactions';\n","import React, { useState, useMemo, useCallback, useEffect, useRef } from 'react';\nimport { preloadImage, isImagePreloaded, formatTime } from '../utils';\nimport type {\n FormatMessageResponse,\n Attachment,\n MessageLabel,\n E2eeAttachmentManifest,\n} from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage, CallType } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useDownloadHandler } from '../hooks/useDownloadHandler';\nimport { E2EE_PREVIEW_MAX_CONCURRENT, useE2eeAttachmentRenderer } from '../hooks/useE2eeAttachmentRenderer';\nimport { buildUserMap } from '../utils';\nimport { MediaLightbox } from './MediaLightbox';\nimport { getFileIcon } from './ChannelInfo/utils';\nimport type { AttachmentProps, MessageRendererProps, MessageBubbleProps, MediaLightboxItem } from '../types';\n\nexport type { AttachmentProps, MessageRendererProps, MessageBubbleProps } from '../types';\nimport { isVoiceRecordingAttachment, isLinkPreviewAttachment, isImage, isVideo, isAudio } from '../messageTypeUtils';\n\n/* ----------------------------------------------------------\n Attachment renderers\n ---------------------------------------------------------- */\nconst ImageAttachment: React.FC<AttachmentProps> = React.memo(\n ({ attachment, onClick }) => {\n const src = attachment.image_url || attachment.thumb_url || attachment.url;\n const thumbSrc = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => {\n preloadImage(src);\n }, [src]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const clickable = Boolean(onClick);\n\n return (\n <div\n className={`ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3${\n clickable ? ' ermis-attachment--clickable' : ''\n }`}\n onClick={onClick}\n role={clickable ? 'button' : undefined}\n tabIndex={clickable ? 0 : undefined}\n >\n {/* Blur placeholder: use thumb if available, otherwise shimmer */}\n {!loaded &&\n (thumbSrc && thumbSrc !== src ? (\n <img className=\"ermis-attachment-blur-preview\" src={thumbSrc} alt=\"\" aria-hidden />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n ))}\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n alt={attachment.file_name || attachment.title || 'image'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n {clickable && (\n <div className=\"ermis-attachment__overlay\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </div>\n )}\n <LocalUploadOverlay attachment={attachment} />\n </div>\n );\n },\n (prev, next) => {\n return (\n attachmentRenderKey(prev.attachment) === attachmentRenderKey(next.attachment) && prev.onClick === next.onClick\n );\n },\n);\n\nfunction isE2eeAttachmentManifest(attachment: unknown): attachment is E2eeAttachmentManifest {\n return Boolean(\n attachment &&\n typeof attachment === 'object' &&\n (attachment as E2eeAttachmentManifest).version === 1 &&\n typeof (attachment as E2eeAttachmentManifest).attachment_id === 'string' &&\n Array.isArray((attachment as E2eeAttachmentManifest).assets),\n );\n}\n\nfunction e2eeDisplayString(display: Record<string, unknown> | undefined, key: string): string | undefined {\n const value = display?.[key];\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction e2eeDisplayNumber(display: Record<string, unknown> | undefined, key: string): number | undefined {\n const value = display?.[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction formatE2eeProgress(progress?: {\n phase: string;\n loaded: number;\n total: number;\n percentage?: number;\n}): string | undefined {\n if (!progress) return undefined;\n const phaseLabel =\n progress.phase === 'granting'\n ? 'Getting access'\n : progress.phase === 'downloading'\n ? 'Downloading'\n : progress.phase === 'verifying'\n ? 'Verifying'\n : progress.phase === 'decrypting'\n ? 'Decrypting'\n : 'Loading';\n if (typeof progress.percentage === 'number') return `${phaseLabel} ${progress.percentage}%`;\n return phaseLabel;\n}\n\nfunction getLocalUploadProgress(attachment: Attachment): number | undefined {\n const value = (attachment as any).upload_progress;\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.min(100, Math.round(value)))\n : undefined;\n}\n\nfunction attachmentRenderKey(attachment: Attachment | E2eeAttachmentManifest): string {\n const anyAttachment = attachment as any;\n const id = isE2eeAttachmentManifest(attachment)\n ? attachment.attachment_id\n : anyAttachment.id || anyAttachment.asset_url || anyAttachment.url || anyAttachment.file_name || '';\n return [\n id,\n anyAttachment.type || '',\n anyAttachment.upload_status || '',\n typeof anyAttachment.upload_progress === 'number' ? Math.round(anyAttachment.upload_progress) : '',\n anyAttachment.local_object_url || '',\n ].join('|');\n}\n\nfunction LocalUploadOverlay({ attachment }: { attachment: Attachment }) {\n const progress = getLocalUploadProgress(attachment);\n const status = (attachment as any).upload_status;\n if (progress === undefined && !status) return null;\n return (\n <span className=\"ermis-attachment-upload-overlay\">\n <span className=\"ermis-e2ee-attachment-spinner\" />\n <span>{progress !== undefined ? `${progress}%` : 'Sending'}</span>\n </span>\n );\n}\n\nfunction e2eeAspectStyle(width?: number, height?: number): React.CSSProperties {\n const ratio = width && height && width > 0 && height > 0 ? width / height : 4 / 3;\n const maxWidth = 340;\n const maxHeight = 420;\n const targetWidth = Math.max(160, Math.min(maxWidth, Math.round(maxHeight * ratio)));\n return {\n aspectRatio: `${width && height ? width : 4} / ${width && height ? height : 3}`,\n width: `min(100%, ${targetWidth}px)`,\n maxWidth: `${maxWidth}px`,\n maxHeight: `${maxHeight}px`,\n };\n}\n\nfunction formatFileSize(size?: number): string | undefined {\n if (!size || size <= 0) return undefined;\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;\n return `${(size / 1024 / 1024).toFixed(1)} MB`;\n}\n\nfunction extensionForName(name: string): string {\n const ext = name.split('.').pop();\n return ext && ext !== name ? ext.toUpperCase() : 'E2EE';\n}\n\nfunction isLikelyImage(name: string, mimeType?: string): boolean {\n return Boolean(mimeType?.startsWith('image/') || /\\.(apng|avif|gif|jpe?g|png|webp)$/i.test(name));\n}\n\nfunction isLikelyVideo(name: string, mimeType?: string): boolean {\n return Boolean(mimeType?.startsWith('video/') || /\\.(mov|m4v|mp4|mpeg|mpg|ogv|webm)$/i.test(name));\n}\n\nfunction isLikelyAudio(name: string, mimeType?: string, attachmentType?: string): boolean {\n return Boolean(\n attachmentType === 'voiceRecording' ||\n mimeType?.startsWith('audio/') ||\n /\\.(aac|flac|m4a|mp3|oga|ogg|opus|wav|webm)$/i.test(name),\n );\n}\n\nfunction E2eePlayIcon() {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n );\n}\n\nlet activeE2eePreviewLoads = 0;\nconst queuedE2eePreviewLoads: Array<() => void> = [];\n\nfunction scheduleE2eePreviewLoad(load: () => Promise<unknown>): void {\n const run = () => {\n activeE2eePreviewLoads += 1;\n void load().finally(() => {\n activeE2eePreviewLoads = Math.max(0, activeE2eePreviewLoads - 1);\n const next = queuedE2eePreviewLoads.shift();\n if (next) next();\n });\n };\n if (activeE2eePreviewLoads < E2EE_PREVIEW_MAX_CONCURRENT) run();\n else queuedE2eePreviewLoads.push(run);\n}\n\nconst E2eeAttachment: React.FC<{ attachment: E2eeAttachmentManifest; grantReady?: boolean }> = React.memo(\n ({ attachment, grantReady = true }) => {\n const { activeChannel } = useChatClient();\n const original = useE2eeAttachmentRenderer(activeChannel, attachment, 'original');\n const preview = useE2eeAttachmentRenderer(activeChannel, attachment, 'preview');\n const [mediaError, setMediaError] = useState(false);\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [naturalPreviewSize, setNaturalPreviewSize] = useState<{ width: number; height: number } | undefined>();\n const previewRef = useRef<HTMLDivElement | null>(null);\n const asset = attachment.assets.find((item) => item.kind === 'original') || attachment.assets[0];\n const previewAsset = attachment.assets.find((item) => item.kind === 'preview');\n const hasPreview = Boolean(previewAsset);\n const display = asset?.display;\n const previewDisplay = previewAsset?.display;\n const title = e2eeDisplayString(display, 'name') || 'Encrypted attachment';\n const mimeType = e2eeDisplayString(display, 'mime_type');\n const attachmentType = e2eeDisplayString(display, 'attachment_type');\n const size = e2eeDisplayNumber(display, 'size') || asset?.plaintext_size || asset?.cipher_size;\n const ext = extensionForName(title);\n const sizeLabel = formatFileSize(size);\n const isImageAsset = isLikelyImage(title, mimeType);\n const isVideoAsset = isLikelyVideo(title, mimeType);\n const isAudioAsset = isLikelyAudio(title, mimeType, attachmentType);\n const loadedUrl = preview.url || original.url;\n const loading = original.loading || preview.loading;\n const error = original.error || preview.error;\n const width =\n e2eeDisplayNumber(display, 'width') || e2eeDisplayNumber(previewDisplay, 'width') || naturalPreviewSize?.width;\n const height =\n e2eeDisplayNumber(display, 'height') || e2eeDisplayNumber(previewDisplay, 'height') || naturalPreviewSize?.height;\n const aspectStyle = e2eeAspectStyle(width, height);\n const progressLabel = formatE2eeProgress(original.progress || preview.progress);\n const statusLabel = mediaError\n ? 'Preview unavailable, download file'\n : !grantReady\n ? 'Sending'\n : progressLabel\n ? progressLabel\n : error\n ? 'Unavailable'\n : original.url\n ? 'Ready'\n : preview.url\n ? 'Preview ready'\n : 'Encrypted';\n\n useEffect(() => {\n if (!grantReady) return;\n if (!hasPreview || !(isImageAsset || isVideoAsset) || preview.url || preview.loading || preview.error) return;\n const element = previewRef.current;\n if (!element || typeof IntersectionObserver === 'undefined') {\n scheduleE2eePreviewLoad(preview.load);\n return;\n }\n let scheduled = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (scheduled) return;\n if (entries.some((entry) => entry.isIntersecting)) {\n scheduled = true;\n observer.disconnect();\n scheduleE2eePreviewLoad(preview.load);\n }\n },\n { rootMargin: '160px' },\n );\n observer.observe(element);\n return () => observer.disconnect();\n }, [grantReady, hasPreview, isImageAsset, isVideoAsset, preview.error, preview.load, preview.loading, preview.url]);\n\n const ensureOriginal = useCallback(() => {\n if (!grantReady) return;\n setMediaError(false);\n if (isVideoAsset && !original.streamUrl && !original.streamLoading) {\n void original.loadStream().then((streamUrl) => {\n if (!streamUrl && !original.url && !original.loading) void original.load();\n });\n return;\n }\n if (!original.url && !original.loading && !original.streamUrl) void original.load();\n }, [grantReady, isVideoAsset, original]);\n\n const openViewer = useCallback(\n (event?: React.MouseEvent) => {\n event?.preventDefault();\n event?.stopPropagation();\n setLightboxOpen(true);\n ensureOriginal();\n },\n [ensureOriginal],\n );\n\n const handleLoad = useCallback(\n (event?: React.MouseEvent) => {\n event?.preventDefault();\n event?.stopPropagation();\n ensureOriginal();\n },\n [ensureOriginal],\n );\n\n const handleDownload = useCallback(\n (event?: React.MouseEvent) => {\n event?.preventDefault();\n event?.stopPropagation();\n if (!grantReady) return;\n void original.download(title);\n },\n [grantReady, original, title],\n );\n\n const lightboxItems = useMemo<MediaLightboxItem[]>(\n () => [\n {\n type: isVideoAsset ? 'video' : 'image',\n src: original.streamUrl || original.url,\n posterSrc: preview.url,\n alt: title,\n loading: original.loading || (lightboxOpen && !original.streamUrl && !original.url && !original.error),\n progressLabel: formatE2eeProgress(original.progress),\n download: async () => {\n await original.download(title);\n },\n onPlaybackError: async () => {\n await original.disposeStream();\n if (!original.url && !original.loading) await original.load();\n },\n onDispose: original.disposeStream,\n },\n ],\n [isVideoAsset, lightboxOpen, original, preview.url, title],\n );\n\n if (isAudioAsset) {\n const durationSec = e2eeDisplayNumber(display, 'duration') || 0;\n const mins = Math.floor(durationSec / 60);\n const secs = Math.round(durationSec % 60);\n const durationLabel = `${mins}:${secs.toString().padStart(2, '0')}`;\n\n return (\n <div className=\"ermis-e2ee-voice-attachment\">\n {original.url ? (\n <CustomAudioPlayer src={original.url} durationLabel={durationLabel} fileName={title} />\n ) : (\n <button\n type=\"button\"\n className=\"ermis-custom-audio-player ermis-custom-audio-player--placeholder\"\n onClick={handleLoad}\n disabled={loading || !grantReady}\n >\n <span className=\"ermis-custom-audio-play-btn\" aria-hidden>\n {loading ? <span className=\"ermis-e2ee-attachment-spinner\" /> : <PlayIcon />}\n </span>\n <span className=\"ermis-custom-audio-progress-container\">\n <span className=\"ermis-custom-audio-progress-bg\">\n <span\n className=\"ermis-custom-audio-progress-fill\"\n style={{ width: `${original.progress?.percentage || 0}%` }}\n />\n </span>\n </span>\n <span className=\"ermis-custom-audio-duration\">{progressLabel || durationLabel}</span>\n <span className=\"ermis-custom-audio-download-btn\" aria-hidden>\n <DownloadIcon />\n </span>\n </button>\n )}\n </div>\n );\n }\n\n if ((isImageAsset || isVideoAsset) && loadedUrl && !mediaError) {\n return (\n <div className=\"ermis-e2ee-attachment-media\" ref={previewRef}>\n <button\n className=\"ermis-e2ee-attachment-placeholder ermis-attachment-aspect-box ermis-attachment-aspect-box--e2ee\"\n style={aspectStyle}\n type=\"button\"\n onClick={openViewer}\n disabled={!grantReady}\n >\n <img\n className=\"ermis-attachment ermis-attachment--image ermis-attachment--loaded\"\n src={loadedUrl}\n alt={title}\n loading=\"lazy\"\n onLoad={(event) => {\n const img = event.currentTarget;\n if (img.naturalWidth && img.naturalHeight) {\n setNaturalPreviewSize({ width: img.naturalWidth, height: img.naturalHeight });\n }\n }}\n onError={() => setMediaError(true)}\n />\n {(isVideoAsset || original.loading) && (\n <span className=\"ermis-e2ee-attachment-placeholder__icon\">\n {original.loading ? <span className=\"ermis-e2ee-attachment-spinner\" /> : <E2eePlayIcon />}\n </span>\n )}\n {original.loading && (\n <span className=\"ermis-e2ee-attachment-progress\">\n {formatE2eeProgress(original.progress) || 'Loading'}\n </span>\n )}\n </button>\n <div className=\"ermis-e2ee-attachment-actions\">\n <span className=\"ermis-e2ee-attachment-actions__label\">{title}</span>\n <button\n className=\"ermis-attachment__file-download\"\n onClick={handleDownload}\n title=\"Download decrypted file\"\n type=\"button\"\n disabled={!grantReady}\n >\n <DownloadIcon />\n </button>\n </div>\n {lightboxOpen && (\n <MediaLightbox items={lightboxItems} isOpen={lightboxOpen} onClose={() => setLightboxOpen(false)} />\n )}\n </div>\n );\n }\n\n if (isImageAsset || isVideoAsset) {\n return (\n <div className=\"ermis-e2ee-attachment-media\" ref={previewRef}>\n <button\n type=\"button\"\n className=\"ermis-e2ee-attachment-placeholder ermis-attachment-aspect-box ermis-attachment-aspect-box--e2ee\"\n style={aspectStyle}\n onClick={handleLoad}\n disabled={loading || !grantReady}\n >\n <span className=\"ermis-attachment-shimmer\" />\n <span className=\"ermis-e2ee-attachment-placeholder__center\">\n <span className=\"ermis-e2ee-attachment-placeholder__icon\">\n {loading ? (\n <span className=\"ermis-e2ee-attachment-spinner\" />\n ) : isVideoAsset ? (\n <E2eePlayIcon />\n ) : (\n getFileIcon(mimeType || 'image/*', title)\n )}\n </span>\n <span className=\"ermis-e2ee-attachment-placeholder__title\">{title}</span>\n <span className=\"ermis-e2ee-attachment-placeholder__meta\">{statusLabel}</span>\n </span>\n </button>\n <div className=\"ermis-e2ee-attachment-actions\">\n <span className=\"ermis-e2ee-attachment-actions__label\">{sizeLabel || 'Encrypted media'}</span>\n <button\n className=\"ermis-attachment__file-download\"\n onClick={handleDownload}\n title=\"Download decrypted file\"\n type=\"button\"\n disabled={loading || !grantReady}\n >\n <DownloadIcon />\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"ermis-attachment ermis-attachment--file ermis-attachment--e2ee\">\n <span className=\"ermis-attachment__file-icon\">\n {getFileIcon(mimeType || '', title)}\n <span className=\"ermis-attachment__file-ext\">{ext}</span>\n </span>\n <button\n type=\"button\"\n className=\"ermis-attachment__file-info ermis-e2ee-attachment__open\"\n onClick={handleLoad}\n disabled={loading || !grantReady}\n >\n <span className=\"ermis-attachment__file-name\">{title}</span>\n <span className=\"ermis-attachment__file-size\">\n {sizeLabel ? `${sizeLabel} · ${statusLabel}` : statusLabel}\n </span>\n </button>\n <button\n className=\"ermis-attachment__file-download\"\n onClick={handleDownload}\n title=\"Download decrypted file\"\n type=\"button\"\n disabled={loading || !grantReady}\n >\n <DownloadIcon />\n </button>\n </div>\n );\n },\n (prev, next) => prev.attachment === next.attachment && prev.grantReady === next.grantReady,\n);\n(E2eeAttachment as any).displayName = 'E2eeAttachment';\n(ImageAttachment as any).displayName = 'ImageAttachment';\n\nconst VideoAttachment: React.FC<AttachmentProps> = React.memo(\n ({ attachment, onClick }) => {\n const src = attachment.asset_url || attachment.url;\n const posterSrc = attachment.image_url || attachment.thumb_url;\n const blurThumb = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = posterSrc ? isImagePreloaded(posterSrc) : true;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (posterSrc) preloadImage(posterSrc);\n }, [posterSrc]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, posterSrc]);\n\n const clickable = Boolean(onClick);\n\n // When clickable (lightbox mode): show poster thumbnail + play icon overlay\n if (clickable) {\n return (\n <div\n className=\"ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3 ermis-attachment--clickable\"\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n >\n {!loaded &&\n (blurThumb && blurThumb !== posterSrc ? (\n <img className=\"ermis-attachment-blur-preview\" src={blurThumb} alt=\"\" aria-hidden />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n ))}\n {posterSrc ? (\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--video-poster${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={posterSrc}\n alt={attachment.file_name || 'video'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n ) : (\n <video\n className={`ermis-attachment ermis-attachment--video${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n />\n )}\n <div className=\"ermis-attachment__overlay\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n <LocalUploadOverlay attachment={attachment} />\n </div>\n );\n }\n\n // Default inline video player (no lightbox)\n return (\n <div className=\"ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3\">\n {!loaded &&\n (blurThumb && blurThumb !== posterSrc ? (\n <img className=\"ermis-attachment-blur-preview\" src={blurThumb} alt=\"\" aria-hidden />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n ))}\n {posterSrc && !loaded && (\n <img\n ref={imgRef}\n src={posterSrc}\n className=\"ermis-attachment--hidden-loader\"\n onLoad={() => setLoaded(true)}\n alt=\"poster-loader\"\n />\n )}\n <video\n className={`ermis-attachment ermis-attachment--video${\n loaded || !posterSrc ? ' ermis-attachment--loaded' : ''\n }`}\n src={src}\n poster={posterSrc}\n controls\n preload=\"metadata\"\n onLoadedData={() => {\n if (!posterSrc) setLoaded(true);\n }}\n />\n <LocalUploadOverlay attachment={attachment} />\n </div>\n );\n },\n (prev, next) => {\n return (\n attachmentRenderKey(prev.attachment) === attachmentRenderKey(next.attachment) && prev.onClick === next.onClick\n );\n },\n);\n(VideoAttachment as any).displayName = 'VideoAttachment';\n\nconst FileAttachment: React.FC<AttachmentProps> = React.memo(\n ({ attachment }) => {\n const url = attachment.url || attachment.asset_url;\n const name = attachment.file_name || attachment.title || 'File';\n const size = attachment.file_size;\n const mimeType = attachment.mime_type || attachment.type || '';\n const ext = name.split('.').pop()?.toUpperCase() || 'FILE';\n\n const { downloadFile } = useDownloadHandler();\n\n const handleDownload = useCallback(\n async (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n await downloadFile(url, name);\n },\n [downloadFile, url, name],\n );\n\n return (\n <div className=\"ermis-attachment ermis-attachment--file\">\n <span className=\"ermis-attachment__file-icon\">\n {getFileIcon(mimeType, name)}\n <span className=\"ermis-attachment__file-ext\">{ext}</span>\n </span>\n <span className=\"ermis-attachment__file-info\">\n <span className=\"ermis-attachment__file-name\">{name}</span>\n {size && (\n <span className=\"ermis-attachment__file-size\">\n {typeof size === 'number' ? `${(size / 1024).toFixed(1)} KB` : size}\n {getLocalUploadProgress(attachment) !== undefined ? ` · ${getLocalUploadProgress(attachment)}%` : ''}\n </span>\n )}\n </span>\n <button className=\"ermis-attachment__file-download\" onClick={handleDownload} title=\"Download\" type=\"button\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n },\n (prev, next) => {\n return attachmentRenderKey(prev.attachment) === attachmentRenderKey(next.attachment);\n },\n);\n(FileAttachment as any).displayName = 'FileAttachment';\n\nconst PlayIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n);\n\nconst PauseIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\" />\n </svg>\n);\n\nconst MicIcon = () => (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n);\n\nconst DownloadIcon = () => (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n);\n\nconst CustomAudioPlayer: React.FC<{ src: string; durationLabel: string; fileName?: string }> = ({\n src,\n durationLabel,\n fileName,\n}) => {\n const [isPlaying, setIsPlaying] = useState(false);\n const [progress, setProgress] = useState(0);\n const [dynamicDuration, setDynamicDuration] = useState(durationLabel);\n const audioRef = React.useRef<HTMLAudioElement>(null);\n const { downloadFile } = useDownloadHandler();\n\n const handleDownload = useCallback(\n async (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n await downloadFile(src, fileName || 'audio.mp3');\n },\n [downloadFile, src, fileName],\n );\n\n React.useEffect(() => {\n const audio = audioRef.current;\n if (!audio) return;\n const updateProgress = () => {\n setProgress((audio.currentTime / audio.duration) * 100 || 0);\n };\n const onEnded = () => {\n setIsPlaying(false);\n setProgress(0);\n };\n const onLoadedMetadata = () => {\n if (audio.duration && audio.duration !== Infinity && durationLabel === '0:00') {\n const mins = Math.floor(audio.duration / 60);\n const secs = Math.floor(audio.duration % 60);\n setDynamicDuration(`${mins}:${secs.toString().padStart(2, '0')}`);\n }\n };\n audio.addEventListener('timeupdate', updateProgress);\n audio.addEventListener('ended', onEnded);\n audio.addEventListener('loadedmetadata', onLoadedMetadata);\n return () => {\n audio.removeEventListener('timeupdate', updateProgress);\n audio.removeEventListener('ended', onEnded);\n audio.removeEventListener('loadedmetadata', onLoadedMetadata);\n };\n }, [durationLabel]);\n\n const togglePlay = () => {\n if (audioRef.current) {\n if (isPlaying) {\n audioRef.current.pause();\n } else {\n audioRef.current.play().catch((e) => console.error(e));\n }\n setIsPlaying(!isPlaying);\n }\n };\n\n const handleSeek = (e: React.MouseEvent<HTMLDivElement>) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const percentage = Math.max(0, Math.min(1, x / rect.width));\n if (audioRef.current && audioRef.current.duration) {\n audioRef.current.currentTime = percentage * audioRef.current.duration;\n setProgress(percentage * 100);\n }\n };\n\n return (\n <div className=\"ermis-custom-audio-player\">\n <button className=\"ermis-custom-audio-play-btn\" onClick={togglePlay} aria-label={isPlaying ? 'Pause' : 'Play'}>\n {isPlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n <div className=\"ermis-custom-audio-progress-container\">\n <div className=\"ermis-custom-audio-progress-bg\" onClick={handleSeek}>\n <div className=\"ermis-custom-audio-progress-fill\" style={{ width: `${progress}%` }} />\n <div className=\"ermis-custom-audio-progress-thumb\" style={{ left: `${progress}%` }} />\n </div>\n </div>\n <span className=\"ermis-custom-audio-duration\">{dynamicDuration}</span>\n <button className=\"ermis-custom-audio-download-btn\" onClick={handleDownload} title=\"Download\" type=\"button\">\n <DownloadIcon />\n </button>\n <audio ref={audioRef} src={src} preload=\"metadata\" className=\"ermis-custom-audio-hidden\" />\n </div>\n );\n};\n\nconst VoiceRecordingAttachment: React.FC<AttachmentProps> = React.memo(\n ({ attachment }) => {\n const src = attachment.asset_url || attachment.url;\n if (!src) return null;\n\n const durationSec = attachment.duration ?? 0;\n const mins = Math.floor(durationSec / 60);\n const secs = Math.round(durationSec % 60);\n const durationLabel = `${mins}:${secs.toString().padStart(2, '0')}`;\n const fileName = attachment.file_name || attachment.title || 'audio.mp3';\n const uploadProgress = getLocalUploadProgress(attachment);\n\n return (\n <div className=\"ermis-voice-upload-wrap\">\n <CustomAudioPlayer src={src} durationLabel={durationLabel} fileName={fileName} />\n {uploadProgress !== undefined && <span className=\"ermis-voice-upload-progress\">{uploadProgress}%</span>}\n </div>\n );\n },\n (prev, next) => {\n return (\n (prev.attachment.asset_url || prev.attachment.url) === (next.attachment.asset_url || next.attachment.url) &&\n getLocalUploadProgress(prev.attachment) === getLocalUploadProgress(next.attachment)\n );\n },\n);\n(VoiceRecordingAttachment as any).displayName = 'VoiceRecordingAttachment';\n\nconst LinkPreviewAttachment: React.FC<AttachmentProps> = React.memo(\n ({ attachment }) => {\n const url = attachment.link_url || attachment.og_scrape_url || attachment.title_link || attachment.url;\n const title = attachment.title;\n const description = attachment.text;\n const image = attachment.image_url;\n\n const alreadyCached = image ? isImagePreloaded(image) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (image) preloadImage(image);\n }, [image]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, image]);\n\n if (!title) return null;\n\n return (\n <a\n className=\"ermis-attachment ermis-attachment--link-preview\"\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {image && (\n <div className=\"ermis-attachment__link-image-wrapper\">\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-attachment__link-image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={image}\n alt={title || 'preview'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n )}\n <div className=\"ermis-attachment__link-info\">\n {title && <span className=\"ermis-attachment__link-title\">{title}</span>}\n {description && <span className=\"ermis-attachment__link-description\">{description}</span>}\n {url && <span className=\"ermis-attachment__link-url\">{new URL(url).hostname}</span>}\n </div>\n </a>\n );\n },\n (prev, next) => {\n return (\n (prev.attachment.link_url || prev.attachment.og_scrape_url || prev.attachment.url) ===\n (next.attachment.link_url || next.attachment.og_scrape_url || next.attachment.url)\n );\n },\n);\n(LinkPreviewAttachment as any).displayName = 'LinkPreviewAttachment';\n\nexport const MessageAttachment: React.FC<AttachmentProps> = ({ attachment }) => {\n if (isImage(attachment)) return <ImageAttachment attachment={attachment} />;\n if (isVideo(attachment)) return <VideoAttachment attachment={attachment} />;\n if (isAudio(attachment)) return <VoiceRecordingAttachment attachment={attachment} />;\n if (isLinkPreviewAttachment(attachment)) return <LinkPreviewAttachment attachment={attachment} />;\n return <FileAttachment attachment={attachment} />;\n};\n\nexport const AttachmentList: React.FC<{\n attachments?: Array<Attachment | E2eeAttachmentManifest>;\n e2eeGrantReady?: boolean;\n}> = React.memo(\n ({ attachments, e2eeGrantReady = true }) => {\n if (!attachments || attachments.length === 0) return null;\n\n // Group by type\n const e2eeAttachments = attachments.filter(isE2eeAttachmentManifest);\n const standardAttachments = attachments.filter((a): a is Attachment => !isE2eeAttachmentManifest(a));\n const media = standardAttachments.filter((a) => isImage(a) || isVideo(a));\n const files = standardAttachments.filter(\n (a) => !isImage(a) && !isVideo(a) && !isVoiceRecordingAttachment(a) && !isLinkPreviewAttachment(a),\n );\n const voices = standardAttachments.filter(isVoiceRecordingAttachment);\n const links = standardAttachments.filter(isLinkPreviewAttachment);\n\n // Lightbox state\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [lightboxIndex, setLightboxIndex] = useState(0);\n\n // Build lightbox items from media attachments\n const lightboxItems = useMemo<MediaLightboxItem[]>(() => {\n return media.map((att) => {\n if (isImage(att)) {\n return {\n type: 'image' as const,\n src: att.image_url || att.thumb_url || att.url || '',\n alt: att.file_name || att.title,\n };\n }\n return {\n type: 'video' as const,\n src: att.asset_url || att.url || '',\n alt: att.file_name || att.title,\n posterSrc: att.image_url || att.thumb_url,\n };\n });\n }, [media]);\n\n const openLightbox = useCallback((index: number) => {\n setLightboxIndex(index);\n setLightboxOpen(true);\n }, []);\n\n const closeLightbox = useCallback(() => {\n setLightboxOpen(false);\n }, []);\n\n const mediaGridClass =\n media.length === 1\n ? 'ermis-attachment-grid ermis-attachment-grid--single'\n : 'ermis-attachment-grid ermis-attachment-grid--multi';\n\n return (\n <div className=\"ermis-attachment-list\">\n {/* Media group: images + videos in grid */}\n {media.length > 0 && (\n <div className={mediaGridClass}>\n {media.map((att, i) =>\n isImage(att) ? (\n <ImageAttachment key={att.id || `img-${i}`} attachment={att} onClick={() => openLightbox(i)} />\n ) : (\n <VideoAttachment key={att.id || `vid-${i}`} attachment={att} onClick={() => openLightbox(i)} />\n ),\n )}\n </div>\n )}\n {/* File group */}\n {e2eeAttachments.map((att) => (\n <E2eeAttachment key={att.attachment_id} attachment={att} grantReady={e2eeGrantReady} />\n ))}\n {files.map((att, i) => (\n <FileAttachment key={att.id || `file-${i}`} attachment={att} />\n ))}\n {/* Voice recording group */}\n {voices.map((att, i) => (\n <VoiceRecordingAttachment key={att.id || `voice-${i}`} attachment={att} />\n ))}\n {/* Link preview group */}\n {links.map((att, i) => (\n <LinkPreviewAttachment key={att.id || `link-${i}`} attachment={att} />\n ))}\n\n {/* Media Lightbox */}\n {lightboxItems.length > 0 && (\n <MediaLightbox\n items={lightboxItems}\n initialIndex={lightboxIndex}\n isOpen={lightboxOpen}\n onClose={closeLightbox}\n />\n )}\n </div>\n );\n },\n (prev, next) => {\n // Skip re-render if same attachment array reference\n if (prev.attachments === next.attachments && prev.e2eeGrantReady === next.e2eeGrantReady) return true;\n if (prev.e2eeGrantReady !== next.e2eeGrantReady) return false;\n if (!prev.attachments || !next.attachments) return false;\n if (prev.attachments.length !== next.attachments.length) return false;\n return prev.attachments.every((a, i) => {\n const b = next.attachments![i];\n return attachmentRenderKey(a) === attachmentRenderKey(b);\n });\n },\n);\n(AttachmentList as any).displayName = 'AttachmentList';\n\n/* ----------------------------------------------------------\n Message renderers by MessageLabel type\n ---------------------------------------------------------- */\n\n/**\n * Detect URLs and emails in plain text, wrapping them in <a> tags.\n * Returns an array of React nodes (strings and link elements).\n */\nconst URL_REGEX = /(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+|[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,})/g;\n\nfunction linkifyText(text: string, keyPrefix: string): React.ReactNode[] {\n const parts = text.split(URL_REGEX);\n if (parts.length === 1) return [text];\n\n return parts.map((part, i) => {\n if (URL_REGEX.test(part)) {\n // Reset lastIndex since we reuse the regex\n URL_REGEX.lastIndex = 0;\n const isEmail = part.includes('@') && !part.startsWith('http');\n const href = isEmail ? `mailto:${part}` : part.startsWith('http') ? part : `https://${part}`;\n return (\n <a\n key={`${keyPrefix}-link-${i}`}\n className=\"ermis-text-link\"\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {part}\n </a>\n );\n }\n // Reset lastIndex\n URL_REGEX.lastIndex = 0;\n return part;\n });\n}\n\n/**\n * Parse message text: render @mentions as highlighted spans,\n * and auto-detect URLs/emails in non-mention text parts.\n */\nfunction renderTextWithMentions(\n text: string,\n message: FormatMessageResponse,\n userMap: Record<string, string>,\n onMentionClick?: (userId: string) => void,\n): React.ReactNode {\n const mentionedUsers: any[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, just linkify the text\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return linkifyText(text, 'txt');\n }\n\n // Build a list of patterns to replace: @userId → @userName\n const replacements: { pattern: string; label: string; id: string }[] = [];\n\n for (const userItem of mentionedUsers) {\n if (!userItem) continue;\n const userId = typeof userItem === 'string' ? userItem : userItem.id;\n if (!userId) continue;\n\n const itemObjName = typeof userItem === 'object' ? userItem.name : undefined;\n const name = userMap[userId] ?? itemObjName ?? userId;\n\n replacements.push({\n pattern: `@${userId}`,\n label: `@${name}`,\n id: userId,\n });\n }\n\n if (mentionedAll) {\n replacements.push({ pattern: '@all', label: '@all', id: 'all' });\n }\n\n // Build a regex that matches any of the mention patterns\n const escaped = replacements.map((r) => r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n const parts = text.split(regex);\n\n // Map from pattern → label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r]));\n\n return parts.flatMap((part, i) => {\n const info = patternToLabel.get(part);\n if (info) {\n // Mention — render as span, do NOT linkify\n return (\n <span\n key={`mention-${i}`}\n className={`ermis-mention${onMentionClick && info.id !== 'all' ? ' ermis-mention--clickable' : ''}`}\n onClick={\n onMentionClick && info.id !== 'all'\n ? (e) => {\n e.stopPropagation();\n onMentionClick(info.id);\n }\n : undefined\n }\n >\n {info.label}\n </span>\n );\n }\n // Non-mention text — linkify URLs/emails\n return linkifyText(part, `p${i}`);\n });\n}\n\n/** Regular message: text with @mentions + attachments */\nexport const RegularMessage: React.FC<MessageRendererProps> = React.memo(\n ({\n message,\n onMentionClick,\n encryptedMessageLabel = 'Encrypted message',\n encryptedMessageFailedLabel = 'Encrypted message could not be decrypted',\n encryptedMessageDecryptingLabel = 'Decrypting encrypted message...',\n }) => {\n const { activeChannel } = useChatClient();\n\n const isEncrypted = message.content_type === 'mls' || Boolean((message as any).mls_ciphertext);\n const hasRawAttachments = Boolean(message.attachments?.length);\n const rawText = message.text || '';\n const isEncryptedSentinelText =\n hasRawAttachments &&\n (rawText === 'Encrypted message' ||\n rawText === 'Encrypted message unavailable' ||\n rawText === encryptedMessageLabel);\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const textContent =\n rawText && !isEncryptedSentinelText ? renderTextWithMentions(rawText, message, userMap, onMentionClick) : null;\n\n const attachmentsToRender = useMemo(() => {\n if (!message.attachments || message.attachments.length === 0) return [];\n\n const text = (message.text || '').trim();\n const URL_REGEX_STRICT = /^(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+)$/;\n const isOnlyUrl = URL_REGEX_STRICT.test(text);\n\n return message.attachments.filter((att) => {\n if (isLinkPreviewAttachment(att)) return isOnlyUrl;\n return true;\n });\n }, [message.attachments, message.text]);\n\n const hasAttachments = attachmentsToRender.length > 0;\n const hasE2eeAttachments = attachmentsToRender.some(isE2eeAttachmentManifest);\n const messageStatus = (message as any).status;\n const e2eeGrantReady = !['sending', 'error', 'failed_offline'].includes(messageStatus);\n const encryptedPlaceholder =\n isEncrypted && !message.text && !hasAttachments ? (\n <span className=\"ermis-message-list__item-text ermis-message-list__item-text--encrypted\">\n {(message as any).e2ee_status === 'failed'\n ? encryptedMessageFailedLabel\n : (message as any).e2ee_status === 'decrypting'\n ? encryptedMessageDecryptingLabel\n : encryptedMessageLabel}\n </span>\n ) : null;\n\n if (hasAttachments) {\n return (\n <div\n className={`ermis-message-content--with-attachments${\n hasE2eeAttachments ? ' ermis-message-content--with-e2ee-attachments' : ''\n }`}\n >\n {textContent && <span className=\"ermis-message-list__item-text\">{textContent}</span>}\n {encryptedPlaceholder}\n <AttachmentList attachments={attachmentsToRender} e2eeGrantReady={e2eeGrantReady} />\n </div>\n );\n }\n\n return (\n <>\n {textContent && <span className=\"ermis-message-list__item-text\">{textContent}</span>}\n {encryptedPlaceholder}\n </>\n );\n },\n (prev, next) => {\n return (\n prev.message.id === next.message.id &&\n prev.message.updated_at === next.message.updated_at &&\n prev.message.text === next.message.text &&\n prev.message.content_type === next.message.content_type &&\n (prev.message as any).status === (next.message as any).status &&\n (prev.message as any).e2ee_status === (next.message as any).e2ee_status &&\n prev.message.attachments === next.message.attachments &&\n prev.isOwnMessage === next.isOwnMessage\n );\n },\n);\nRegularMessage.displayName = 'RegularMessage';\n\n/** System message: centered info text, parsed from raw format */\nexport const SystemMessage: React.FC<MessageRendererProps> = ({ message, systemMessageTranslations }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const parsedText = useMemo(\n () => (message.text ? parseSystemMessage(message.text, userMap, systemMessageTranslations) : ''),\n [message.text, userMap, systemMessageTranslations],\n );\n\n return <span className=\"ermis-message-list__system-text\">{parsedText || message.text}</span>;\n};\n\n/** Signal message: call events */\nexport const SignalMessage: React.FC<MessageRendererProps> = ({ message, signalMessageTranslations }) => {\n const { client } = useChatClient();\n\n const rawText = message.text ?? '';\n const result = rawText ? parseSignalMessage(rawText, client.userID || '', signalMessageTranslations) : null;\n\n if (!result) {\n return <span className=\"ermis-message-list__signal-text\">{rawText}</span>;\n }\n\n const isSuccess = !!result.duration;\n const colorModifier = isSuccess ? 'success' : 'missed';\n const isAudio = result.callType === CallType.AUDIO;\n\n return (\n <div className=\"ermis-signal-message\">\n <div className={`ermis-signal-message__icon ermis-signal-message__icon--${colorModifier}`}>\n {isAudio ? (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" />\n </svg>\n ) : (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polygon points=\"23 7 16 12 23 17 23 7\" />\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-signal-message__body\">\n <span className={`ermis-signal-message__text ermis-signal-message__text--${colorModifier}`}>{result.text}</span>\n {result.duration && <span className=\"ermis-signal-message__duration\">{result.duration}</span>}\n </div>\n <span className=\"ermis-signal-message__time\">{formatTime(message.created_at)}</span>\n </div>\n );\n};\n\n/** Poll message */\nexport const PollMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <div className=\"ermis-message-poll\">\n <span className=\"ermis-message-poll__icon\">📊</span>\n <span className=\"ermis-message-poll__text\">{message.text || 'Poll'}</span>\n </div>\n);\n\n/** Sticker message */\nexport const StickerMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const stickerUrl = (message as any).sticker_url;\n\n const alreadyCached = stickerUrl ? isImagePreloaded(stickerUrl) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (stickerUrl) preloadImage(stickerUrl);\n }, [stickerUrl]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, stickerUrl]);\n\n if (stickerUrl) {\n return (\n <div className=\"ermis-message-sticker-wrapper\">\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-message-sticker${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={stickerUrl}\n alt=\"sticker\"\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n );\n }\n return <span className=\"ermis-message-list__item-text\">{message.text}</span>;\n};\n\n/** Error message */\nexport const ErrorMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <span className=\"ermis-message-error\">{message.text || 'Message failed'}</span>\n);\n\n/**\n * Map from MessageLabel → component.\n * Consumer can override individual renderers via the `messageRenderers` prop.\n */\nexport const defaultMessageRenderers: Record<MessageLabel, React.ComponentType<MessageRendererProps>> = {\n regular: RegularMessage,\n system: SystemMessage,\n signal: SignalMessage,\n poll: PollMessage,\n sticker: StickerMessage,\n error: ErrorMessage,\n};\n","import React from 'react';\nimport type { MediaTab } from '../../types';\n\nexport function getFileIcon(contentType: string, fileName: string): React.ReactNode {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n\n if (contentType.includes('pdf') || ext === 'pdf') {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n );\n }\n\n if (contentType.includes('zip') || contentType.includes('rar') || contentType.includes('archive') || ['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 8v13H3V3h13\" />\n <path d=\"M16 3v5h5\" />\n <path d=\"M10 12h4M10 16h4M10 8h1\" />\n </svg>\n );\n }\n\n // Default file icon\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n );\n}\n\nexport const ROLE_WEIGHTS: Record<string, number> = {\n owner: 4,\n moder: 3,\n member: 2,\n pending: 1,\n};\n\nexport const MESSAGING_TABS: MediaTab[] = ['media', 'links', 'files'];\nexport const ALL_TABS: MediaTab[] = ['members', 'media', 'links', 'files'];\n\nexport const PENDING_STYLE = { opacity: 0.7, transition: 'opacity 0.15s ease' } as const;\nexport const READY_STYLE = { opacity: 1, transition: 'opacity 0.15s ease' } as const;\n","import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport {\n ATTACHMENT_TYPES,\n isImageAttachment,\n isLinkPreviewAttachment,\n isStickerMessage,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n} from '../messageTypeUtils';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { PinnedMessageItemProps, PinnedMessagesProps } from '../types';\n\n/* ----------------------------------------------------------\n Default PinnedMessageItem\n ---------------------------------------------------------- */\nconst DefaultPinnedMessageItem: React.FC<PinnedMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n onClickMessage,\n onUnpin,\n AvatarComponent,\n unpinLabel = 'Unpin message',\n stickerLabel = 'Sticker',\n attachmentLabel = 'Attachment',\n unavailableMessageLabel = 'Message unavailable',\n}) => {\n const { activeChannel } = useChatClient();\n const userName = message.user?.name || message.user_id || 'Unknown';\n const userAvatar = message.user?.avatar;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n let previewText = message.text || '';\n const isSticker = isStickerMessage(message);\n\n const isUnavailable =\n !previewText &&\n ((message as any).content_type === 'mls' ||\n Boolean((message as any).mls_ciphertext) ||\n (message as any).e2ee_status === 'failed' ||\n (message as any).e2ee_status === 'decrypting');\n\n if (isUnavailable) {\n previewText = unavailableMessageLabel;\n } else if (!previewText && hasAttachments) {\n const firstAttach = message.attachments![0];\n previewText =\n (isLinkPreviewAttachment(firstAttach) && firstAttach.title) ||\n firstAttach.title ||\n firstAttach.file_name ||\n attachmentLabel;\n } else if (isSticker) {\n previewText = stickerLabel;\n }\n\n // Convert @userId → @UserName in preview text\n if (previewText) {\n previewText = replaceMentionsForPreview(previewText, message, userMap);\n }\n\n // Attachment icon prefix\n let attachIcon = '';\n if (!isUnavailable && hasAttachments) {\n const firstAttach = message.attachments![0];\n if (isImageAttachment(firstAttach)) attachIcon = '📷 ';\n else if (isVideoAttachment(firstAttach)) attachIcon = '🎥 ';\n else if (isVoiceRecordingAttachment(firstAttach) || firstAttach.type === ATTACHMENT_TYPES.AUDIO) {\n attachIcon = '🎵 ';\n }\n else attachIcon = '📄 ';\n } else if (isSticker) {\n attachIcon = '😀 ';\n }\n\n return (\n <div\n className={`ermis-pinned-messages__item ${isOwnMessage ? 'ermis-pinned-messages__item--own' : ''}`}\n onClick={() => onClickMessage?.(message.id)}\n role=\"button\"\n tabIndex={0}\n >\n <AvatarComponent image={userAvatar} name={userName} size={38} />\n <div className=\"ermis-pinned-messages__item-content\">\n <span className=\"ermis-pinned-messages__item-user\">{userName}</span>\n <span className=\"ermis-pinned-messages__item-text\">{attachIcon}{previewText || unavailableMessageLabel}</span>\n </div>\n <button\n className=\"ermis-pinned-messages__unpin-btn\"\n onClick={(e) => { e.stopPropagation(); onUnpin?.(message.id); }}\n title={unpinLabel}\n aria-label={unpinLabel}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\" />\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </button>\n </div>\n );\n});\nDefaultPinnedMessageItem.displayName = 'DefaultPinnedMessageItem';\n\n/* ----------------------------------------------------------\n PinnedMessages component\n ---------------------------------------------------------- */\nexport const PinnedMessages: React.FC<PinnedMessagesProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n PinnedMessageItemComponent = DefaultPinnedMessageItem,\n onClickMessage,\n maxCollapsed = 1,\n pinnedMessagesLabel,\n seeAllLabel = 'See all',\n collapseLabel = 'Collapse',\n unpinLabel = 'Unpin message',\n stickerLabel = 'Sticker',\n attachmentLabel = 'Attachment',\n unavailableMessageLabel = 'Message unavailable',\n}) => {\n const { activeChannel, client, messages } = useChatClient();\n const [expanded, setExpanded] = useState(false);\n const currentUserId = client.userID;\n\n // Reset expanded state when switching channels\n useEffect(() => {\n setExpanded(false);\n }, [activeChannel]);\n\n const pinnedMessages = useMemo<FormatMessageResponse[]>(() => {\n if (!activeChannel) return [];\n const pinned = (activeChannel.state as any)?.pinnedMessages;\n return Array.isArray(pinned) ? pinned : [];\n }, [activeChannel, messages]);\n\n const toggleExpanded = useCallback(() => {\n setExpanded((prev) => !prev);\n }, []);\n\n const handleUnpin = useCallback(async (messageId: string) => {\n if (!activeChannel) return;\n try {\n await activeChannel.unpinMessage(messageId);\n } catch (err) {\n console.error('Failed to unpin message', err);\n }\n }, [activeChannel]);\n\n if (pinnedMessages.length === 0) return null;\n\n const displayedMessages = expanded\n ? pinnedMessages\n : pinnedMessages.slice(0, maxCollapsed);\n\n const hasMore = pinnedMessages.length > maxCollapsed;\n\n return (\n <div className={`ermis-pinned-messages${expanded ? ' ermis-pinned-messages--expanded' : ''}${className ? ` ${className}` : ''}`}>\n {/* Header bar */}\n <div className=\"ermis-pinned-messages__header\" onClick={toggleExpanded}>\n <svg className=\"ermis-pinned-messages__icon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n <span className=\"ermis-pinned-messages__label\">\n {typeof pinnedMessagesLabel === 'function'\n ? pinnedMessagesLabel(pinnedMessages.length)\n : pinnedMessagesLabel || `${pinnedMessages.length} pinned message${pinnedMessages.length > 1 ? 's' : ''}`\n }\n </span>\n {hasMore && (\n <button\n className=\"ermis-pinned-messages__toggle\"\n onClick={(e) => { e.stopPropagation(); toggleExpanded(); }}\n >\n {expanded ? collapseLabel : seeAllLabel}\n </button>\n )}\n </div>\n\n {/* Pinned message list */}\n <div className=\"ermis-pinned-messages__list\">\n {displayedMessages.map((msg) => (\n <PinnedMessageItemComponent\n key={msg.id}\n message={msg}\n isOwnMessage={msg.user_id === currentUserId || msg.user?.id === currentUserId}\n onClickMessage={onClickMessage}\n onUnpin={handleUnpin}\n AvatarComponent={AvatarComponent}\n unpinLabel={unpinLabel}\n stickerLabel={stickerLabel}\n attachmentLabel={attachmentLabel}\n unavailableMessageLabel={unavailableMessageLabel}\n />\n ))}\n </div>\n </div>\n );\n});\n\nPinnedMessages.displayName = 'PinnedMessages';\n","import React from 'react';\nimport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\nimport { Avatar } from './Avatar';\nimport { formatReadTimestamp } from '../utils';\n\nexport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\n\n/* ----------------------------------------------------------\n Default Tooltip — shown on hover\n ---------------------------------------------------------- */\nconst DefaultReadReceiptsTooltip: React.FC<ReadReceiptsTooltipProps> = React.memo(({\n readers,\n AvatarComponent,\n}) => (\n <div className=\"ermis-read-receipts__tooltip-wrapper\">\n <div className=\"ermis-read-receipts__tooltip\">\n {readers.map((reader) => (\n <div key={reader.id} className=\"ermis-read-receipts__tooltip-item\">\n <AvatarComponent\n image={reader.avatar}\n name={reader.name || reader.id}\n size={20}\n />\n <div className=\"ermis-read-receipts__tooltip-info\">\n <span className=\"ermis-read-receipts__tooltip-name\">{reader.name || reader.id}</span>\n <span className=\"ermis-read-receipts__tooltip-time\">{formatReadTimestamp(reader.last_read)}</span>\n </div>\n </div>\n ))}\n </div>\n </div>\n));\nDefaultReadReceiptsTooltip.displayName = 'DefaultReadReceiptsTooltip';\n\n/* ----------------------------------------------------------\n ReadReceipts — main component\n ---------------------------------------------------------- */\nexport const ReadReceipts: React.FC<ReadReceiptsProps> = React.memo(({\n readers,\n maxAvatars = 5,\n AvatarComponent = Avatar,\n TooltipComponent = DefaultReadReceiptsTooltip,\n showTooltip = true,\n isOwnMessage,\n}) => {\n // Only render when there are actual readers (avatar-based display)\n // Sent/Sending/Error status icons are now rendered inline inside the message bubble\n if (!readers || readers.length === 0) {\n return null;\n }\n\n const visible = readers.slice(0, maxAvatars);\n const overflow = readers.length - maxAvatars;\n\n return (\n <div className={`ermis-read-receipts${isOwnMessage ? ' ermis-read-receipts--own' : ' ermis-read-receipts--other'}`}>\n <div className=\"ermis-read-receipts__avatars\">\n {visible.map((reader) => (\n <AvatarComponent\n key={reader.id}\n image={reader.avatar}\n name={reader.name || reader.id}\n size={16}\n className=\"ermis-read-receipts__avatar\"\n />\n ))}\n {overflow > 0 && (\n <span className=\"ermis-read-receipts__overflow\">+{overflow}</span>\n )}\n {showTooltip && (\n <TooltipComponent\n readers={readers}\n AvatarComponent={AvatarComponent}\n />\n )}\n </div>\n </div>\n );\n});\n\nReadReceipts.displayName = 'ReadReceipts';\n","import React from 'react';\nimport { useTypingIndicator, type TypingUser } from '../hooks/useTypingIndicator';\n\nexport type TypingIndicatorProps = {\n /** Custom render function for the typing text (I18n) */\n typingIndicatorLabel?: (users: TypingUser[]) => string;\n /** Custom render function for the typing text (JSX) */\n renderText?: (users: TypingUser[]) => React.ReactNode;\n};\n\n/**\n * Displays a \"X is typing...\" indicator below the message list.\n * Automatically subscribes to typing events via the useTypingIndicator hook.\n */\nexport const TypingIndicator: React.FC<TypingIndicatorProps> = React.memo(({ typingIndicatorLabel, renderText }) => {\n const { typingUsers } = useTypingIndicator();\n\n const isActive = typingUsers.length > 0;\n\n let text: React.ReactNode = null;\n if (isActive) {\n if (renderText) {\n text = renderText(typingUsers);\n } else if (typingIndicatorLabel) {\n text = typingIndicatorLabel(typingUsers);\n } else {\n text = formatTypingText(typingUsers);\n }\n }\n\n return (\n <div className={`ermis-typing-indicator-wrapper`}>\n {isActive && (\n <div className=\"ermis-typing-indicator ermis-typing-indicator--active\">\n <div className=\"ermis-typing-indicator__dots\">\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n </div>\n <span className=\"ermis-typing-indicator__text\">{text}</span>\n </div>\n )}\n </div>\n );\n});\n\nTypingIndicator.displayName = 'TypingIndicator';\n\n/**\n * Format typing text based on number of users:\n * - 1 user: \"Alice is typing...\"\n * - 2 users: \"Alice and Bob are typing...\"\n * - 3+ users: \"Alice, Bob and 2 others are typing...\"\n */\nfunction formatTypingText(users: TypingUser[]): string {\n const names = users.map((u) => u.name || u.id);\n\n if (names.length === 1) {\n return `${names[0]} is typing...`;\n }\n if (names.length === 2) {\n return `${names[0]} and ${names[1]} are typing...`;\n }\n const remaining = names.length - 2;\n return `${names[0]}, ${names[1]} and ${remaining} other${remaining > 1 ? 's' : ''} are typing...`;\n}\n","import { useState, useEffect, useRef } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\nexport type TypingUser = {\n id: string;\n name?: string;\n};\n\n/**\n * Hook that subscribes to typing events on the active channel\n * and returns the list of currently‑typing users (excluding the current user).\n *\n * Stale entries are auto‑cleaned every 7 seconds, consistent with\n * the SDK's `channel.state.clean()` behaviour.\n */\nexport function useTypingIndicator() {\n const { activeChannel, client } = useChatClient();\n const [typingUsers, setTypingUsers] = useState<TypingUser[]>([]);\n const currentUserId = client.userID;\n\n // Keep a mutable map so event handlers can read/write without\n // creating stale‑closure issues.\n const typingMapRef = useRef<Map<string, { user: TypingUser; timestamp: number }>>(new Map());\n\n useEffect(() => {\n if (!activeChannel) {\n setTypingUsers([]);\n typingMapRef.current.clear();\n return;\n }\n\n // Reset when channel switches\n typingMapRef.current.clear();\n setTypingUsers([]);\n\n const syncState = () => {\n const users = Array.from(typingMapRef.current.values()).map((v) => v.user);\n setTypingUsers(users);\n };\n\n const handleTypingStart = (event: Event) => {\n const userId = event.user?.id;\n if (!userId || userId === currentUserId) return;\n\n typingMapRef.current.set(userId, {\n user: { id: userId, name: event.user?.name },\n timestamp: Date.now(),\n });\n syncState();\n };\n\n const handleTypingStop = (event: Event) => {\n const userId = event.user?.id;\n if (!userId) return;\n\n typingMapRef.current.delete(userId);\n syncState();\n };\n\n const sub1 = activeChannel.on('typing.start', handleTypingStart);\n const sub2 = activeChannel.on('typing.stop', handleTypingStop);\n\n // Auto‑clean stale entries every 7 seconds\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n let changed = false;\n for (const [uid, entry] of typingMapRef.current.entries()) {\n if (now - entry.timestamp > 7000) {\n typingMapRef.current.delete(uid);\n changed = true;\n }\n }\n if (changed) syncState();\n }, 3000);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n clearInterval(cleanupInterval);\n typingMapRef.current.clear();\n };\n }, [activeChannel, currentUserId]);\n\n return { typingUsers };\n}\n","import React from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type PendingOverlayProps = {\n channelImage?: string;\n channelName?: string;\n title: string;\n subtitle: string;\n acceptLabel: string;\n rejectLabel: string;\n onAccept: () => void;\n onReject: () => void;\n /** Label for the skip button (direct messaging channels) */\n skipLabel?: string;\n /** Handler for the skip action (direct messaging channels) */\n onSkip?: () => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n};\n\nexport const PendingOverlay: React.FC<PendingOverlayProps> = React.memo(({\n channelImage,\n channelName,\n title,\n subtitle,\n acceptLabel,\n rejectLabel,\n onAccept,\n onReject,\n skipLabel,\n onSkip,\n AvatarComponent,\n}) => (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <AvatarComponent image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{title}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{subtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n {onSkip ? (\n <button className=\"ermis-message-list__reject-btn\" onClick={onSkip}>{skipLabel || 'Skip'}</button>\n ) : (\n <button className=\"ermis-message-list__reject-btn\" onClick={onReject}>{rejectLabel}</button>\n )}\n <button className=\"ermis-message-list__accept-btn\" onClick={onAccept}>{acceptLabel}</button>\n </div>\n </div>\n </div>\n));\n\nPendingOverlay.displayName = 'PendingOverlay';\n","import React from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type SkippedOverlayProps = {\n channelImage?: string;\n channelName?: string;\n title: string;\n subtitle: string;\n acceptLabel: string;\n onAccept: () => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n};\n\nexport const SkippedOverlay: React.FC<SkippedOverlayProps> = React.memo(({\n channelImage,\n channelName,\n title,\n subtitle,\n acceptLabel,\n onAccept,\n AvatarComponent,\n}) => (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <AvatarComponent image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{title}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{subtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n <button className=\"ermis-message-list__accept-btn\" onClick={onAccept}>{acceptLabel}</button>\n </div>\n </div>\n </div>\n));\n\nSkippedOverlay.displayName = 'SkippedOverlay';\n","import React from 'react';\n\nexport type BannedOverlayProps = {\n isBlocked?: boolean;\n blockedTitle: string;\n bannedTitle: string;\n blockedSubtitle: string;\n bannedSubtitle: string;\n onUnblock?: () => void;\n};\n\nexport const BannedOverlay: React.FC<BannedOverlayProps> = React.memo(({\n isBlocked,\n blockedTitle,\n bannedTitle,\n blockedSubtitle,\n bannedSubtitle,\n onUnblock,\n}) => (\n <div className=\"ermis-message-list__banned-overlay\">\n <div className=\"ermis-message-list__banned-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__banned-overlay-title\">{isBlocked ? blockedTitle : bannedTitle}</span>\n <span className=\"ermis-message-list__banned-overlay-subtitle\">{isBlocked ? blockedSubtitle : bannedSubtitle}</span>\n {isBlocked && onUnblock && (\n <button\n className=\"ermis-message-list__unblock-btn\"\n onClick={onUnblock}\n >\n Unblock\n </button>\n )}\n </div>\n));\n\nBannedOverlay.displayName = 'BannedOverlay';\n","import React from 'react';\n\nexport type ClosedTopicOverlayProps = {\n title: string;\n subtitle: string;\n canManageTopic: boolean;\n reopenLabel: string;\n onReopen?: () => void;\n};\n\nexport const ClosedTopicOverlay: React.FC<ClosedTopicOverlayProps> = React.memo(({\n title,\n subtitle,\n canManageTopic,\n reopenLabel,\n onReopen,\n}) => (\n <div className=\"ermis-message-list__closed-overlay\">\n <div className=\"ermis-message-list__closed-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__closed-overlay-title\">{title}</span>\n <span className=\"ermis-message-list__closed-overlay-subtitle\">{subtitle}</span>\n {canManageTopic && onReopen && (\n <button\n className=\"ermis-message-list__reopen-btn\"\n onClick={onReopen}\n >\n {reopenLabel}\n </button>\n )}\n </div>\n));\n\nClosedTopicOverlay.displayName = 'ClosedTopicOverlay';\n","import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useMentions } from '../hooks/useMentions';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useEmojiPicker } from '../hooks/useEmojiPicker';\nimport { useStickerPicker } from '../hooks/useStickerPicker';\nimport { useMessageSend } from '../hooks/useMessageSend';\nimport { useDragAndDrop } from '../hooks/useDragAndDrop';\nimport { DefaultSendButton, DefaultAttachButton, DefaultEmojiButton, DefaultStickerButton, DefaultStickerPicker, DefaultDragAndDropOverlay, DefaultVoiceRecordButton } from './MessageInputDefaults';\nimport { MentionSuggestions } from './MentionSuggestions';\nimport { FilesPreview } from './FilesPreview';\nimport { ReplyPreview } from './ReplyPreview';\nimport { EditPreview } from './EditPreview';\nimport { PreviewOverlay } from './PreviewOverlay';\nimport { usePreviewState } from '../hooks/usePreviewState';\nimport { buildUserMap, replaceMentionsForPreview, moveCaretToEnd, countWords } from '../utils';\nimport { getMentionHtml } from '../hooks/useMentions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { CHANNEL_ROLES } from '../channelRoleUtils';\nimport { isTopicChannel } from '../channelTypeUtils';\nimport type { MentionMember, MessageInputProps, FilePreviewItem } from '../types';\n\nexport type { MessageInputProps, SendButtonProps, AttachButtonProps, EmojiPickerProps, EmojiButtonProps } from '../types';\n\nexport const MessageInput: React.FC<MessageInputProps> = React.memo(({\n placeholder = 'Type a message...',\n onSend,\n className,\n SendButton = DefaultSendButton,\n AttachButton = DefaultAttachButton,\n FilesPreviewComponent = FilesPreview,\n MentionSuggestionsComponent = MentionSuggestions,\n disableAttachments = false,\n disableMentions = false,\n renderAbove,\n onBeforeSend,\n EmojiPickerComponent,\n EmojiButtonComponent = DefaultEmojiButton,\n StickerPickerComponent = DefaultStickerPicker,\n StickerButtonComponent = DefaultStickerButton,\n VoiceRecordButtonComponent = DefaultVoiceRecordButton,\n disableStickers = false,\n stickerIframeUrl = 'https://sticker.ermis.network',\n ReplyPreviewComponent = ReplyPreview,\n EditPreviewComponent = EditPreview,\n bannedLabel = 'You have been banned from this channel',\n blockedLabel = 'You have blocked this user. Unblock to send messages.',\n linksDisabledLabel = 'Message blocked: Sending links is disabled for members.',\n keywordBlockedLabel = (match: string) => `Message blocked: Contains restricted word \"${match}\".`,\n sendDisabledLabel = 'Sending messages is disabled in this channel.',\n slowModeLabel = (cooldown: number) => (\n <>Slow mode is active. You can send another message in <strong>{cooldown}s</strong>.</>\n ),\n closedTopicLabel = 'This topic is closed.',\n PreviewOverlayComponent = PreviewOverlay,\n previewOverlayTitle = 'You are viewing a public channel.',\n joinChannelLabel = 'Join Channel',\n replyingToLabel,\n editingMessageLabel,\n dragAndDropLabel = 'Drop files here to upload',\n DragAndDropOverlayComponent = DefaultDragAndDropOverlay,\n maxCharsLabel = 'Tin nhắn không được vượt quá 5000 ký tự.',\n}) => {\n const { client, activeChannel, syncMessages, quotedMessage, setQuotedMessage, editingMessage, setEditingMessage, setDraft, getDraft } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n const { isPreviewMode } = usePreviewState(activeChannel, client.userID);\n const editableRef = React.useRef<HTMLDivElement>(null);\n const [hasContent, setHasContent] = useState(false);\n const prevChannelCidRef = useRef<string | null>(null);\n\n const { role, isGroupChannel: isTeamChannel, hasCapability } = useChannelCapabilities();\n const isTopic = isTopicChannel(activeChannel);\n const isClosedTopic = activeChannel?.data?.is_closed_topic === true;\n\n // Slow Mode Logic\n const [memberMessageCooldown, setMemberMessageCooldown] = useState(Number(activeChannel?.data?.member_message_cooldown) || 0);\n\n useEffect(() => {\n if (!activeChannel) return;\n setMemberMessageCooldown(Number(activeChannel.data?.member_message_cooldown) || 0);\n const handleUpdate = (event: Record<string, unknown>) => {\n const channelData = (event?.channel as Record<string, unknown>) || activeChannel.data;\n setMemberMessageCooldown(Number(channelData?.member_message_cooldown) || 0);\n };\n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const isSlowModeApplied = isTeamChannel && role === CHANNEL_ROLES.MEMBER && memberMessageCooldown > 0;\n\n const [cooldownEnd, setCooldownEnd] = useState<number | null>(null);\n const [cooldown, setCooldown] = useState(0);\n const lastMsgSentAtRef = useRef<number>(0);\n\n // Initialize cooldown state periodically or on change\n useEffect(() => {\n if (!isSlowModeApplied) {\n setCooldownEnd(null);\n setCooldown(0);\n return;\n }\n\n let lastMsgSentAt = lastMsgSentAtRef.current || 0;\n const messages = activeChannel?.state?.messages || [];\n\n // Iterate from newest to oldest to find actual highest timestamp\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].user?.id === client.userID) {\n const msgTime = new Date(messages[i].created_at).getTime();\n if (msgTime && !isNaN(msgTime) && msgTime > lastMsgSentAt) {\n lastMsgSentAt = msgTime;\n }\n break;\n }\n }\n\n if (lastMsgSentAt) {\n const cdEnd = lastMsgSentAt + memberMessageCooldown;\n if (cdEnd > Date.now()) {\n setCooldownEnd(cdEnd);\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n }, [isSlowModeApplied, activeChannel, memberMessageCooldown, client.userID]);\n\n // Tick the countdown visualization\n useEffect(() => {\n if (!cooldownEnd || cooldownEnd <= Date.now()) {\n setCooldown(0);\n return;\n }\n const updateCd = () => {\n const remaining = cooldownEnd - Date.now();\n if (remaining <= 0) {\n setCooldown(0);\n } else {\n setCooldown(Math.ceil(remaining / 1000));\n }\n };\n updateCd();\n const timer = setInterval(updateCd, 1000);\n return () => clearInterval(timer);\n }, [cooldownEnd]);\n\n const isSlowModeBlocked = isSlowModeApplied && cooldown > 0 && !editingMessage;\n\n const canSendMessage = hasCapability('send-message');\n const canSendLinks = hasCapability('send-links');\n\n const [keywordError, setKeywordError] = useState<string | null>(null);\n\n // Auto-clear link restriction banner if admin suddenly restores the capability\n useEffect(() => {\n if (keywordError?.includes('links') && canSendLinks) {\n setKeywordError(null);\n }\n }, [canSendLinks, keywordError]);\n\n const localOnBeforeSend = useCallback(async (text: string, attachments: FilePreviewItem[]) => {\n // Permission validation: Send Links\n if (!canSendLinks && text) {\n // Basic URL matching config\n const urlRegex = /(https?:\\/\\/[^\\s]+)|(www\\.[^\\s]+)|([a-zA-Z0-9-]+\\.[a-zA-Z]{2,}(\\/[^\\s]*)?)/i;\n if (urlRegex.test(text)) {\n setKeywordError(linksDisabledLabel);\n return false;\n }\n }\n\n // Max Characters validation (5000 chars)\n if (text && text.length > 5000) {\n setKeywordError(maxCharsLabel);\n return false;\n }\n\n // Custom Keyword validation\n const words = (activeChannel?.data?.filter_words as string[]) || [];\n if (words.length > 0 && text) {\n const lowerText = text.toLowerCase();\n const match = words.find(w => lowerText.includes(w.toLowerCase()));\n if (match) {\n setKeywordError(keywordBlockedLabel(match));\n // We could also visually shake the input box here\n return false;\n }\n }\n setKeywordError(null);\n if (onBeforeSend) {\n return await onBeforeSend(text, attachments);\n }\n return true;\n }, [activeChannel, onBeforeSend, canSendLinks]);\n\n const handleMessageSent = useCallback((text: string) => {\n if (isSlowModeApplied) {\n lastMsgSentAtRef.current = Date.now();\n setCooldownEnd(Date.now() + memberMessageCooldown);\n }\n // Clear draft after successful send\n if (activeChannel?.cid) {\n setDraft(activeChannel.cid, { html: '', files: [] });\n }\n onSend?.(text);\n }, [isSlowModeApplied, memberMessageCooldown, onSend, activeChannel, setDraft]);\n\n // Auto-focus when channel changes or when reply/edit is selected\n useEffect(() => {\n if (activeChannel && editableRef.current) {\n editableRef.current.focus();\n }\n }, [activeChannel, quotedMessage, editingMessage]);\n\n\n /* ---------- Hooks ---------- */\n const {\n files, setFiles, fileInputRef,\n handleFilesSelected, handleRemoveFile, handleAttachClick, cleanupFiles,\n } = useFileUpload({ activeChannel, editableRef, setHasContent });\n\n const filesRef = useRef(files);\n filesRef.current = files;\n\n const { isDragging } = useDragAndDrop(\n handleFilesSelected,\n disableAttachments || !canSendMessage || isSlowModeBlocked || !!editingMessage || !!quotedMessage\n );\n\n // Pre-fill text and legacy attachments when editingMessage is set\n useEffect(() => {\n if (editingMessage && editableRef.current) {\n // 1. Prefill text content\n const rawText = editingMessage.text || '';\n\n // Extract user map locally since we have `activeChannel.state.members`\n const userMap = buildUserMap(activeChannel?.state);\n\n const htmlText = rawText\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\n/g, '<br>');\n\n editableRef.current.innerHTML = replaceMentionsForPreview(\n htmlText,\n editingMessage,\n userMap,\n getMentionHtml\n );\n\n // Move cursor to the end\n moveCaretToEnd(editableRef.current);\n\n // The API does not support attachment modifications during edits.\n // Flush any active files and only allow text/mention modifications.\n setFiles([]);\n setHasContent(!!editingMessage.text);\n }\n }, [editingMessage, setFiles]);\n\n // Cleanup blob URLs on unmount\n useEffect(() => {\n return () => cleanupFiles();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n } = useEmojiPicker({ editableRef, setHasContent });\n\n const {\n stickerPickerOpen,\n toggleStickerPicker,\n closeStickerPicker,\n } = useStickerPicker({ activeChannel, stickerIframeUrl });\n\n // Build member list from channel state (only for team channels and topics)\n const members = useMemo<MentionMember[]>(() => {\n if (!(isTeamChannel || isTopic)) return [];\n const list: MentionMember[] = [];\n const stateMembers = activeChannel?.state?.members as Record<string, unknown> | undefined;\n if (stateMembers && typeof stateMembers === 'object') {\n for (const [id, memberVal] of Object.entries(stateMembers)) {\n const member = memberVal as Record<string, any>;\n list.push({\n id,\n name: member?.user?.name || member?.user_id || id,\n avatar: member?.user?.avatar,\n });\n }\n }\n return list;\n }, [activeChannel, isTeamChannel, isTopic]);\n\n const {\n showSuggestions, filteredMembers, highlightIndex,\n handleInput: mentionHandleInput,\n handleKeyDown: mentionHandleKeyDown,\n selectMention, buildPayload, reset,\n } = useMentions({\n members,\n currentUserId: client.userID,\n editableRef,\n });\n\n const cancelEdit = useCallback(() => {\n setEditingMessage(null);\n cleanupFiles();\n setFiles([]);\n setHasContent(false);\n reset();\n if (editableRef.current) {\n editableRef.current.innerHTML = '';\n }\n }, [setEditingMessage, cleanupFiles, setFiles, setHasContent, reset]);\n\n const { sending, handleSend } = useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel: isTeamChannel || isTopic,\n buildPayload,\n reset,\n syncMessages,\n onSend: handleMessageSent,\n onBeforeSend: localOnBeforeSend,\n quotedMessage,\n clearQuotedMessage: () => setQuotedMessage(null),\n editingMessage,\n clearEditingMessage: () => setEditingMessage(null),\n });\n\n useEffect(() => {\n // Save draft from PREVIOUS channel before switching\n if (prevChannelCidRef.current && editableRef.current) {\n const currentHtml = editableRef.current.innerHTML;\n setDraft(prevChannelCidRef.current, { html: currentHtml, files: filesRef.current });\n }\n\n reset();\n handleEmojiClose();\n // Do not revoke Object URLs here since we save files in drafts and need previews when returning\n setFiles([]);\n\n // Restore draft for NEW channel\n const newCid = activeChannel?.cid || null;\n prevChannelCidRef.current = newCid;\n\n if (newCid && editableRef.current) {\n const draft = getDraft(newCid);\n if (draft) {\n editableRef.current.innerHTML = draft.html;\n setFiles(draft.files || []);\n setHasContent(!!editableRef.current.textContent?.trim() || !!(draft.files && draft.files.length));\n moveCaretToEnd(editableRef.current);\n } else {\n editableRef.current.innerHTML = '';\n setFiles([]);\n setHasContent(false);\n }\n } else {\n if (editableRef.current) editableRef.current.innerHTML = '';\n setFiles([]);\n setHasContent(false);\n }\n\n // Stop typing indicator on channel switch / unmount\n return () => {\n activeChannel?.stopTyping();\n };\n }, [activeChannel, reset, handleEmojiClose, setFiles, setDraft, getDraft]);\n\n /* ---------- Input event handlers ---------- */\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n const content = el?.textContent?.trim() ?? '';\n setHasContent(content.length > 0 || files.length > 0);\n setKeywordError(null); // clear keyword error if user modifies input\n if ((isTeamChannel || isTopic) && !disableMentions) {\n mentionHandleInput();\n }\n // Send typing indicator (SDK throttles to 1 event per 2s)\n activeChannel?.keystroke();\n }, [isTeamChannel, isTopic, disableMentions, mentionHandleInput, files.length, activeChannel]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Prevent reacting to \"Enter\" when constructing characters with an IME (e.g. Vietnamese telex)\n if (e.nativeEvent.isComposing) return;\n\n if (e.key === 'Escape') {\n if (editingMessage) {\n cancelEdit();\n return;\n }\n if (quotedMessage) {\n setQuotedMessage(null);\n return;\n }\n }\n if ((isTeamChannel || isTopic) && !disableMentions) {\n const consumed = mentionHandleKeyDown(e);\n if (consumed) return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n if (!isSlowModeBlocked && !keywordError) {\n handleSend();\n }\n }\n },\n [isTeamChannel, isTopic, disableMentions, mentionHandleKeyDown, handleSend, editingMessage, quotedMessage, setEditingMessage, setQuotedMessage, reset],\n );\n\n const handlePaste = useCallback((e: React.ClipboardEvent) => {\n e.preventDefault();\n if (e.clipboardData.files && e.clipboardData.files.length > 0) {\n if (!disableAttachments && canSendMessage && !isSlowModeBlocked && !editingMessage) {\n handleFilesSelected(e.clipboardData.files);\n }\n return;\n }\n const plainText = e.clipboardData.getData('text/plain');\n if (plainText) {\n document.execCommand('insertText', false, plainText);\n }\n }, [disableAttachments, canSendMessage, isSlowModeBlocked, editingMessage, handleFilesSelected]);\n\n if (!activeChannel) return null;\n\n // Don't show input for pending invitations at all\n if (isPending) return null;\n\n // Show banned banner instead of input\n if (isBanned) {\n return (\n <div className={`ermis-message-input ermis-message-input--banned${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{bannedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show blocked banner instead of input (messaging channels only)\n if (isBlocked) {\n return (\n <div className={`ermis-message-input ermis-message-input--blocked${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__blocked-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{blockedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show closed topic banner instead of input\n if (isClosedTopic) {\n return (\n <div className={`ermis-message-input ermis-message-input--closed${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__closed-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n <span>{closedTopicLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show Preview Overlay for public channels when the user has not joined\n if (isPreviewMode) {\n return (\n <PreviewOverlayComponent\n title={previewOverlayTitle}\n buttonLabel={joinChannelLabel}\n onJoin={async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.acceptInvite('join');\n // Optimistically update local membership\n if (activeChannel.state && client.userID) {\n const updatedMembership = {\n ...activeChannel.state.membership,\n channel_role: 'member',\n user_id: client.userID,\n } as Record<string, unknown>;\n activeChannel.state.membership = updatedMembership;\n if (activeChannel.state.members?.[client.userID]) {\n activeChannel.state.members[client.userID] = {\n ...activeChannel.state.members[client.userID],\n channel_role: 'member',\n };\n }\n // Dispatch synthetic event so channel list and other hooks update\n client.dispatchEvent({\n type: 'member.joined',\n cid: activeChannel.cid,\n channel_type: activeChannel.type,\n channel_id: activeChannel.id,\n channel: activeChannel.data,\n member: updatedMembership,\n user: client.user,\n } as any);\n }\n } catch (e) {\n console.error('Failed to join public channel', e);\n }\n }}\n className={className}\n />\n );\n }\n\n const isStillUploading = files.some((f) => f.status === 'uploading');\n\n return (\n <div className={`ermis-message-input${className ? ` ${className}` : ''}`}>\n {/* Reply preview */}\n {quotedMessage && !editingMessage && (\n <ReplyPreviewComponent\n message={quotedMessage}\n onDismiss={() => setQuotedMessage(null)}\n replyingToLabel={replyingToLabel}\n />\n )}\n\n {/* Edit preview */}\n {editingMessage && (\n <EditPreviewComponent\n message={editingMessage}\n onDismiss={cancelEdit}\n editingMessageLabel={editingMessageLabel}\n />\n )}\n\n {/* Custom content above input */}\n {renderAbove?.()}\n\n {/* File previews */}\n {!disableAttachments && <FilesPreviewComponent files={files} onRemove={handleRemoveFile} />}\n\n {/* Keyword Error Banner */}\n {keywordError && (\n <div className=\"ermis-message-input__keyword-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n {keywordError}\n </div>\n )}\n\n {/* Permission Disabled Banner */}\n {!canSendMessage && !editingMessage && (\n <div className=\"ermis-message-input__permission-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\n {sendDisabledLabel}\n </div>\n )}\n\n {/* Slow Mode Cooldown Banner */}\n {canSendMessage && isSlowModeBlocked && !keywordError && (\n <div className=\"ermis-message-input__slow-mode-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><polyline points=\"12 6 12 12 16 14\"></polyline></svg>\n {typeof slowModeLabel === 'function' ? slowModeLabel(cooldown) : slowModeLabel}\n </div>\n )}\n\n {/* Text input + send row */}\n <div className={`ermis-message-input__row${(!canSendMessage || isSlowModeBlocked || keywordError) ? ' ermis-message-input__row--banners-active' : ''}`}>\n <div className=\"ermis-message-input__editable-wrapper\">\n {canSendMessage && (isTeamChannel || isTopic) && !disableMentions && showSuggestions && (\n <MentionSuggestionsComponent\n members={filteredMembers}\n highlightIndex={highlightIndex}\n onSelect={selectMention}\n />\n )}\n\n {/* Attach button */}\n {!disableAttachments && (\n <AttachButton disabled={sending || !!editingMessage || isSlowModeBlocked || !canSendMessage} onClick={handleAttachClick} />\n )}\n\n {/* Hidden file input */}\n {!disableAttachments && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"ermis-message-input__file-input\"\n onChange={(e) => {\n handleFilesSelected(e.target.files);\n e.target.value = '';\n }}\n disabled={!!editingMessage || isSlowModeBlocked || !canSendMessage}\n />\n )}\n\n <div\n ref={editableRef}\n className=\"ermis-message-input__editable\"\n contentEditable={!sending && !isSlowModeBlocked && canSendMessage}\n role=\"textbox\"\n aria-placeholder={placeholder}\n data-placeholder={placeholder}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n suppressContentEditableWarning\n />\n\n {/* Voice record button */}\n {VoiceRecordButtonComponent && (\n <VoiceRecordButtonComponent\n disabled={sending || !!editingMessage || isSlowModeBlocked || !canSendMessage}\n onRecordComplete={(f) => {\n const dt = new DataTransfer();\n dt.items.add(f);\n handleFilesSelected(dt.files);\n }}\n />\n )}\n\n {/* Emoji button — shown only when EmojiPickerComponent is provided */}\n {EmojiPickerComponent && (\n <EmojiButtonComponent active={emojiPickerOpen} onClick={isSlowModeBlocked ? () => { } : toggleEmojiPicker} />\n )}\n\n {/* Sticker button — shown unless disabled */}\n {!disableStickers && StickerButtonComponent && (\n <StickerButtonComponent active={stickerPickerOpen} onClick={isSlowModeBlocked || !!editingMessage || !!quotedMessage ? () => { } : toggleStickerPicker} />\n )}\n </div>\n\n <SendButton disabled={!hasContent || sending || !!editingMessage || isSlowModeBlocked || !canSendMessage || isStillUploading || !!keywordError} onClick={handleSend} />\n </div>\n\n {/* Emoji Picker Dropdown */}\n {EmojiPickerComponent && emojiPickerOpen && (\n <div className=\"ermis-message-input__emoji-picker\">\n <EmojiPickerComponent onSelect={handleEmojiSelect} onClose={handleEmojiClose} />\n </div>\n )}\n\n {/* Sticker Picker Dropdown */}\n {!disableStickers && StickerPickerComponent && stickerPickerOpen && (\n <StickerPickerComponent stickerIframeUrl={stickerIframeUrl} onClose={closeStickerPicker} />\n )}\n\n {/* Drag & Drop Overlay */}\n {isDragging && (\n <DragAndDropOverlayComponent dragAndDropLabel={dragAndDropLabel} />\n )}\n </div>\n );\n});\n\nMessageInput.displayName = 'MessageInput';\n","import { useState, useCallback, useRef, useDeferredValue, useMemo } from 'react';\nimport { moveCaretAfterNode } from '../utils';\nimport type {\n MentionMember,\n MentionPayload,\n UseMentionsOptions,\n UseMentionsReturn,\n} from '../types';\n\nexport type { MentionMember, MentionPayload, UseMentionsOptions, UseMentionsReturn } from '../types';\n\nexport const MENTION_SPAN_CLASS = 'ermis-message-input__mention-span';\n\n/**\n * Returns the raw HTML string for a mention span, useful for initializing contenteditable divs.\n */\nexport function getMentionHtml(userId: string, displayName: string): string {\n const safeName = displayName.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n return `<span class=\"${MENTION_SPAN_CLASS}\" data-mention-id=\"${userId}\" contenteditable=\"false\">@${safeName}</span> `;\n}\n\n/**\n * Insert an atomic mention <span> at the current cursor position inside a\n * contenteditable element, followed by a trailing space.\n */\nfunction insertMentionAtCursor(\n editableEl: HTMLElement,\n userId: string,\n displayName: string,\n) {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n\n const { startContainer, startOffset } = range;\n if (startContainer.nodeType === Node.TEXT_NODE) {\n const textBefore = startContainer.textContent?.slice(0, startOffset) ?? '';\n const atIndex = textBefore.lastIndexOf('@');\n if (atIndex !== -1) {\n range.setStart(startContainer, atIndex);\n range.deleteContents();\n }\n }\n\n const span = document.createElement('span');\n span.className = MENTION_SPAN_CLASS;\n span.setAttribute('data-mention-id', userId);\n span.contentEditable = 'false';\n span.textContent = `@${displayName}`;\n\n range.insertNode(span);\n\n const space = document.createTextNode('\\u00A0');\n span.after(space);\n moveCaretAfterNode(space);\n\n editableEl.dispatchEvent(new Event('input', { bubbles: true }));\n}\n\n/**\n * Parse the DOM of a contenteditable div to produce a mention payload.\n */\nfunction buildPayloadFromDOM(editableEl: HTMLElement): MentionPayload {\n let text = '';\n let mentionedAll = false;\n const mentionedUsers: string[] = [];\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? '';\n return;\n }\n\n if (node instanceof HTMLElement) {\n const mentionId = node.getAttribute('data-mention-id');\n if (mentionId && node.classList.contains(MENTION_SPAN_CLASS)) {\n if (mentionId === '__all__') {\n mentionedAll = true;\n text += '@all';\n } else {\n if (!mentionedUsers.includes(mentionId)) {\n mentionedUsers.push(mentionId);\n }\n text += `@${mentionId}`;\n }\n return;\n }\n\n if (node.tagName === 'BR') {\n text += '\\n';\n return;\n }\n\n if (node.tagName === 'DIV' && text.length > 0 && !text.endsWith('\\n')) {\n text += '\\n';\n }\n }\n\n node.childNodes.forEach(walk);\n }\n\n walk(editableEl);\n text = text.replace(/\\u00A0/g, ' ').trim();\n\n return { text, mentioned_all: mentionedAll, mentioned_users: mentionedUsers };\n}\n\n/**\n * Scan the DOM for currently present mention spans and return their IDs.\n */\nfunction getActiveMentionIds(editableEl: HTMLElement): Set<string> {\n const ids = new Set<string>();\n const spans = editableEl.querySelectorAll(`.${MENTION_SPAN_CLASS}`);\n spans.forEach((span) => {\n const id = span.getAttribute('data-mention-id');\n if (id) ids.add(id);\n });\n return ids;\n}\n\n/**\n * Binary search to find the first index where the name starts with the given prefix.\n */\nfunction findFirstMatchIndex(arr: MentionMember[], prefix: string): number {\n let low = 0;\n let high = arr.length - 1;\n let result = -1;\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n const name = (arr[mid].name || '').toLowerCase();\n\n if (name.startsWith(prefix)) {\n result = mid; // Found match, keep searching left for the first one\n high = mid - 1;\n } else if (name < prefix) {\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return result;\n}\n\nexport function useMentions({\n members,\n currentUserId,\n editableRef,\n}: UseMentionsOptions): UseMentionsReturn {\n const [showSuggestions, setShowSuggestions] = useState(false);\n const [query, setQuery] = useState('');\n const [highlightIndex, setHighlightIndex] = useState(0);\n const [activeMentionIds, setActiveMentionIds] = useState<Set<string>>(new Set());\n\n const deferredQuery = useDeferredValue(query);\n\n // All item: special entry\n const allItem: MentionMember = useMemo(\n () => ({ id: '__all__', name: 'all' }),\n [],\n );\n\n // Pre-sort members for binary range search\n const sortedMembers = useMemo(() => {\n return [...members].sort((a, b) => {\n const nameA = (a.name || '').toLowerCase();\n const nameB = (b.name || '').toLowerCase();\n if (nameA < nameB) return -1;\n if (nameA > nameB) return 1;\n return 0;\n });\n }, [members]);\n\n // Filter members based on deferred query, exclude self and already-mentioned\n const filteredMembers = useMemo(() => {\n const q = deferredQuery.toLowerCase();\n\n // Start with @all if not already selected\n const result: MentionMember[] = [];\n if (!activeMentionIds.has('__all__')) {\n if (!q || 'all'.startsWith(q)) {\n result.push(allItem);\n }\n }\n\n if (!q) {\n for (const m of sortedMembers) {\n if (m.id === currentUserId) continue; // skip self\n result.push(m);\n if (result.length >= 50) break;\n }\n return result;\n }\n\n // Range search using binary search\n const startIndex = findFirstMatchIndex(sortedMembers, q);\n if (startIndex !== -1) {\n for (let i = startIndex; i < sortedMembers.length; i++) {\n const m = sortedMembers[i];\n const name = (m.name || '').toLowerCase();\n \n if (!name.startsWith(q)) break; // End of range\n \n if (m.id === currentUserId) continue; // skip self\n result.push(m);\n if (result.length >= 50) break;\n }\n }\n\n return result;\n }, [sortedMembers, deferredQuery, activeMentionIds, currentUserId, allItem]);\n\n // Detect @ trigger from cursor position\n const detectTrigger = useCallback((): { triggered: boolean; query: string } => {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) {\n return { triggered: false, query: '' };\n }\n\n const { anchorNode, anchorOffset } = sel;\n if (!anchorNode || anchorNode.nodeType !== Node.TEXT_NODE) {\n return { triggered: false, query: '' };\n }\n\n const textBefore = anchorNode.textContent?.slice(0, anchorOffset) ?? '';\n\n // Find the last @ that is preceded by a space or is at the start\n const match = textBefore.match(/(^|[\\s\\u00A0])@(\\S*)$/);\n if (!match) {\n return { triggered: false, query: '' };\n }\n\n return { triggered: true, query: match[2] };\n }, []);\n\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n if (!el) return;\n\n // Update active mention IDs by scanning DOM\n setActiveMentionIds(getActiveMentionIds(el));\n\n // Detect @ trigger\n const result = detectTrigger();\n if (result.triggered) {\n setShowSuggestions(true);\n setQuery(result.query);\n setHighlightIndex(0);\n } else {\n setShowSuggestions(false);\n setQuery('');\n }\n }, [editableRef, detectTrigger]);\n\n const selectMention = useCallback(\n (member: MentionMember) => {\n const el = editableRef.current;\n if (!el) return;\n\n insertMentionAtCursor(el, member.id, member.name);\n\n // Update tracking\n setActiveMentionIds((prev) => new Set(prev).add(member.id));\n setShowSuggestions(false);\n setQuery('');\n\n // Re-focus the editable\n el.focus();\n },\n [editableRef],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent): boolean => {\n if (!showSuggestions || filteredMembers.length === 0) return false;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev < filteredMembers.length - 1 ? prev + 1 : 0,\n );\n return true;\n\n case 'ArrowUp':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev > 0 ? prev - 1 : filteredMembers.length - 1,\n );\n return true;\n\n case 'Enter':\n e.preventDefault();\n if (filteredMembers[highlightIndex]) {\n selectMention(filteredMembers[highlightIndex]);\n }\n return true;\n\n case 'Escape':\n e.preventDefault();\n setShowSuggestions(false);\n return true;\n\n default:\n return false;\n }\n },\n [showSuggestions, filteredMembers, highlightIndex, selectMention],\n );\n\n const buildPayload = useCallback((): MentionPayload => {\n const el = editableRef.current;\n if (!el) return { text: '', mentioned_all: false, mentioned_users: [] };\n return buildPayloadFromDOM(el);\n }, [editableRef]);\n\n const reset = useCallback(() => {\n setShowSuggestions(false);\n setQuery('');\n setHighlightIndex(0);\n setActiveMentionIds(new Set());\n const el = editableRef.current;\n if (el) {\n el.innerHTML = '';\n }\n }, [editableRef]);\n\n return {\n showSuggestions,\n filteredMembers,\n highlightIndex,\n handleInput,\n handleKeyDown,\n selectMention,\n buildPayload,\n reset,\n };\n}\n","import React, { useState, useRef, useEffect } from 'react';\nimport { MultiRecorder, PCM_WORKLET_URL } from 'react-ts-audio-recorder';\nimport type { VoiceRecordButtonProps } from '../types';\n\n/* ----------------------------------------------------------\n Default sub-components for MessageInput\n ---------------------------------------------------------- */\n\nexport const DefaultSendButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__send-btn\"\n onClick={onClick}\n disabled={disabled}\n >\n Send\n </button>\n));\nDefaultSendButton.displayName = 'DefaultSendButton';\n\nexport const DefaultAttachButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__attach-btn\"\n onClick={onClick}\n type=\"button\"\n aria-label=\"Attach files\"\n disabled={disabled}\n >\n 📎\n </button>\n));\nDefaultAttachButton.displayName = 'DefaultAttachButton';\n\nexport const DefaultEmojiButton: React.FC<{ active: boolean; onClick: () => void }> = React.memo(({\n active,\n onClick,\n}) => (\n <button\n className={`ermis-message-input__emoji-btn${active ? ' ermis-message-input__emoji-btn--active' : ''}`}\n onClick={onClick}\n type=\"button\"\n aria-label=\"Emoji\"\n >\n 😀\n </button>\n));\nDefaultEmojiButton.displayName = 'DefaultEmojiButton';\n\nexport const DefaultStickerButton: React.FC<{ active: boolean; onClick: () => void }> = React.memo(({\n active,\n onClick,\n}) => (\n <button\n className={`ermis-message-input__sticker-btn${active ? ' ermis-message-input__sticker-btn--active' : ''}`}\n onClick={onClick}\n type=\"button\"\n aria-label=\"Sticker\"\n >\n 🐱\n </button>\n));\nDefaultStickerButton.displayName = 'DefaultStickerButton';\n\nexport const DefaultStickerPicker: React.FC<{ stickerIframeUrl: string; onClose: () => void }> = React.memo(({\n stickerIframeUrl,\n}) => (\n <div className=\"ermis-message-input__sticker-picker-container\">\n <iframe\n src={stickerIframeUrl}\n title=\"Sticker Picker\"\n className=\"ermis-message-input__sticker-iframe\"\n />\n </div>\n));\nDefaultStickerPicker.displayName = 'DefaultStickerPicker';\n\nexport const DefaultDragAndDropOverlay: React.FC<{ dragAndDropLabel: string }> = React.memo(({\n dragAndDropLabel,\n}) => (\n <div className=\"ermis-channel__drop-overlay\">\n <div className=\"ermis-channel__drop-overlay-content\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\n <polyline points=\"17 8 12 3 7 8\"></polyline>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"></line>\n </svg>\n <span>{dragAndDropLabel}</span>\n </div>\n </div>\n));\nDefaultDragAndDropOverlay.displayName = 'DefaultDragAndDropOverlay';\n\nexport const DefaultVoiceRecordButton: React.FC<VoiceRecordButtonProps> = React.memo(({ disabled, onRecordComplete }) => {\n const [isRecording, setIsRecording] = useState(false);\n const [recordingTime, setRecordingTime] = useState(0);\n const recorderRef = useRef<MultiRecorder | null>(null);\n const timerRef = useRef<number | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current) clearInterval(timerRef.current);\n if (recorderRef.current) recorderRef.current.close();\n };\n }, []);\n\n const toggleRecording = async () => {\n if (isRecording) {\n if (!recorderRef.current) return;\n try {\n const blob = await recorderRef.current.stopRecording();\n const file = new File([blob], `Voice_Message.wav`, { type: 'audio/wav' });\n onRecordComplete(file);\n } catch (err) {\n console.error('Failed to stop recording:', err);\n } finally {\n recorderRef.current.close();\n recorderRef.current = null;\n setIsRecording(false);\n setRecordingTime(0);\n if (timerRef.current) clearInterval(timerRef.current);\n }\n } else {\n try {\n const recorder = new MultiRecorder({\n format: 'wav',\n workletURL: PCM_WORKLET_URL,\n });\n await recorder.init();\n await recorder.startRecording();\n recorderRef.current = recorder;\n setIsRecording(true);\n setRecordingTime(0);\n timerRef.current = window.setInterval(() => {\n setRecordingTime(prev => prev + 1);\n }, 1000);\n } catch (err) {\n console.error('Failed to start recording:', err);\n }\n }\n };\n\n const formatTime = (seconds: number) => {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n };\n\n return (\n <button\n className={`ermis-message-input__voice-btn ${isRecording ? 'ermis-message-input__voice-btn--recording' : ''}`}\n onClick={toggleRecording}\n disabled={disabled && !isRecording}\n type=\"button\"\n title={isRecording ? 'Stop Recording' : 'Record Voice Message'}\n >\n {isRecording ? (\n <span className=\"ermis-message-input__voice-recording-indicator\">\n <span className=\"ermis-message-input__voice-dot\" />\n {formatTime(recordingTime)}\n </span>\n ) : (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"22\" />\n </svg>\n )}\n </button>\n );\n});\nDefaultVoiceRecordButton.displayName = 'DefaultVoiceRecordButton';\n","import React, { useEffect, useRef } from 'react';\nimport { Avatar } from './Avatar';\nimport type { MentionSuggestionsProps } from '../types';\n\nexport type { MentionSuggestionsProps } from '../types';\n\nexport const MentionSuggestions: React.FC<MentionSuggestionsProps> = React.memo(({\n members,\n highlightIndex,\n onSelect,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const itemsRef = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // Auto-scroll highlighted item into view\n useEffect(() => {\n const el = itemsRef.current.get(highlightIndex);\n if (el && containerRef.current) {\n const container = containerRef.current;\n const elementTop = el.offsetTop;\n const elementBottom = elementTop + el.offsetHeight;\n const containerTop = container.scrollTop;\n const containerBottom = containerTop + container.clientHeight;\n\n if (elementTop < containerTop) {\n container.scrollTop = elementTop;\n } else if (elementBottom > containerBottom) {\n container.scrollTop = elementBottom - container.clientHeight;\n }\n }\n }, [highlightIndex]);\n\n if (members.length === 0) return null;\n\n return (\n <div \n className=\"ermis-mention-suggestions\" \n ref={containerRef}\n style={{ overflowY: 'auto', maxHeight: '200px' }}\n >\n {members.map((member, index) => (\n <div\n key={member.id}\n ref={(el) => {\n if (el) itemsRef.current.set(index, el);\n else itemsRef.current.delete(index);\n }}\n className={`ermis-mention-suggestions__item${\n index === highlightIndex ? ' ermis-mention-suggestions__item--highlighted' : ''\n }`}\n onMouseDown={(e) => {\n // Use mousedown (not click) to fire before blur\n e.preventDefault();\n onSelect(member);\n }}\n >\n {member.id === '__all__' ? (\n <div className=\"ermis-mention-suggestions__all-icon\">@</div>\n ) : (\n <Avatar image={member.avatar} name={member.name} size={24} />\n )}\n <span className=\"ermis-mention-suggestions__name\">\n {member.id === '__all__' ? 'all' : member.name}\n </span>\n </div>\n ))}\n </div>\n );\n});\n\nMentionSuggestions.displayName = 'MentionSuggestions';\n","import React from 'react';\nimport { isHeicFile } from '@ermis-network/ermis-chat-sdk';\nimport type { FilesPreviewProps } from '../types';\n\nexport type { FilePreviewItem, FilesPreviewProps } from '../types';\n/**\n * Format file size into human-readable string.\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Get a display icon for non-previewable file types.\n */\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.startsWith('audio/')) return '🎵';\n if (mimeType.startsWith('video/')) return '🎬';\n if (mimeType.includes('pdf')) return '📄';\n if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('tar')) return '📦';\n return '📎';\n}\n\n/**\n * FilesPreview — renders selected files with thumbnails and remove buttons.\n * Shown above the text input area in MessageInput.\n */\nexport const FilesPreview: React.FC<FilesPreviewProps> = React.memo(({ files, onRemove }) => {\n if (files.length === 0) return null;\n\n return (\n <div className=\"ermis-files-preview\">\n {files.map((item) => {\n const fileType = item.file?.type || item.originalAttachment?.mime_type || '';\n const fileName = item.file?.name || item.originalAttachment?.title || 'Unknown file';\n const fileSize = item.file?.size || item.originalAttachment?.file_size || 0;\n\n const isHeic = item.file ? isHeicFile(item.file) : fileType === 'image/heic' || fileType === 'image/heif';\n const isImage = fileType.startsWith('image/') && !isHeic;\n const isVideo = fileType.startsWith('video/');\n const isUploading = item.status === 'uploading';\n const hasError = item.status === 'error';\n\n const previewUrl = item.previewUrl || item.originalAttachment?.image_url || item.originalAttachment?.asset_url;\n\n return (\n <div\n key={item.id}\n className={`ermis-files-preview__item${hasError ? ' ermis-files-preview__item--error' : ''}`}\n >\n {/* Remove button */}\n <button\n className=\"ermis-files-preview__remove\"\n onClick={() => onRemove(item.id)}\n aria-label=\"Remove file\"\n type=\"button\"\n >\n ✕\n </button>\n\n {/* Preview content */}\n {isImage && previewUrl ? (\n <img className=\"ermis-files-preview__thumb\" src={previewUrl} alt={fileName} />\n ) : isVideo && previewUrl ? (\n <video className=\"ermis-files-preview__thumb\" src={previewUrl} muted />\n ) : (\n <div className=\"ermis-files-preview__file-icon\">\n <span>{getFileIcon(fileType)}</span>\n </div>\n )}\n\n {/* File info */}\n <div className=\"ermis-files-preview__info\">\n <span className=\"ermis-files-preview__name\">{fileName}</span>\n <span className=\"ermis-files-preview__size\">{formatFileSize(Number(fileSize))}</span>\n </div>\n\n {/* Upload status overlay */}\n {isUploading && (\n <div className=\"ermis-files-preview__uploading\">\n {item.progress !== undefined ? (\n <span className=\"ermis-files-preview__progress\">{item.progress}%</span>\n ) : (\n <span className=\"ermis-files-preview__spinner\" />\n )}\n </div>\n )}\n\n {/* Error overlay */}\n {hasError && (\n <div className=\"ermis-files-preview__error-badge\" title={item.error}>\n ⚠\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n});\n\nFilesPreview.displayName = 'FilesPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport type { ReplyPreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const ReplyPreview: React.FC<ReplyPreviewProps> = React.memo(({\n message,\n onDismiss,\n replyingToLabel = 'Replying to',\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n \n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = isStickerMessage(message);\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{replyingToLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel reply\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nReplyPreview.displayName = 'ReplyPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const EditPreview: React.FC<{\n message: FormatMessageResponse;\n onDismiss: () => void;\n editingMessageLabel?: string;\n}> = React.memo(({\n message,\n onDismiss,\n editingMessageLabel = 'Editing message',\n}: any) => {\n console.log('--message--', message)\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n\n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = isStickerMessage(message);\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{editingMessageLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel edit\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nEditPreview.displayName = 'EditPreview';\n","import React from 'react';\nimport type { PreviewOverlayProps } from '../types';\n\nexport const PreviewOverlay: React.FC<PreviewOverlayProps> = ({\n title = 'You are viewing a public channel.',\n buttonLabel = 'Join Channel',\n onJoin,\n className = '',\n}) => {\n return (\n <div className={`ermis-preview-overlay ${className}`}>\n <span className=\"ermis-preview-overlay__text\">{title}</span>\n <button\n className=\"ermis-preview-overlay__button\"\n onClick={onJoin}\n type=\"button\"\n >\n {buttonLabel}\n </button>\n </div>\n );\n};\n\nPreviewOverlay.displayName = 'PreviewOverlay';\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type {\n EncryptedChannelRepairMode,\n EncryptedChannelRepairResult,\n RepairMode,\n RepairResult,\n RestoreProgressRecord,\n} from '@ermis-network/ermis-chat-sdk';\n\nimport { useChatClient } from './useChatClient';\n\nexport type RecoveryPinStatus = 'idle' | 'working' | 'ready' | 'locked' | 'error';\n\nexport type RecoveryStatusInfo = {\n hasVault: boolean;\n unlocked: boolean;\n hasIncompleteRestore: boolean;\n incompleteChannels: string[];\n channelsWithPermanentGaps: string[];\n restoreProgressWithIssues: RestoreProgressRecord[];\n e2eeBootstrapRunning?: boolean;\n e2eeBootstrapCompleted?: number;\n e2eeBootstrapTotal?: number;\n};\n\nexport type RecoveryRestoredMessage = {\n epoch: number;\n messageId?: string;\n plaintext?: unknown;\n source?: 'archive';\n createdAt?: string;\n gap?: boolean;\n reason?: string;\n};\n\nexport type UseRecoveryPinReturn = {\n status: RecoveryPinStatus;\n error: Error | null;\n hasRecoveryKey: boolean;\n recoveryStatus: RecoveryStatusInfo | null;\n setupRecoveryPin: (pin: string) => Promise<void>;\n unlockRecoveryVault: (pin: string) => Promise<void>;\n changeRecoveryPin: (oldPin: string, newPin: string) => Promise<void>;\n changeUnlockedRecoveryPin: (newPin: string) => Promise<void>;\n repairRecoveryChannel: (\n channelType: string,\n channelId: string,\n options?: { mode?: RepairMode },\n ) => Promise<RepairResult>;\n repairEncryptedChannel: (\n channelType: string,\n channelId: string,\n options?: { mode?: EncryptedChannelRepairMode },\n ) => Promise<EncryptedChannelRepairResult>;\n enqueueRestore: (\n channelType: string,\n channelId: string,\n priority?: 'active' | 'background',\n options?: { fromEpoch?: number; toEpoch?: number },\n ) => void;\n loadRestoreProgress: (channelType: string, channelId: string) => Promise<RestoreProgressRecord | null>;\n restoreHistoricalMessages: (\n channelType: string,\n channelId: string,\n options?: { fromEpoch?: number; toEpoch?: number },\n ) => Promise<RecoveryRestoredMessage[]>;\n refresh: () => void;\n};\n\nconst requireEncryptionManager = (client: unknown): any => {\n const manager = (client as any)?.encryptionManager;\n if (!manager) {\n throw new Error('Encryption manager is not initialized.');\n }\n return manager;\n};\n\nexport const useRecoveryPin = (): UseRecoveryPinReturn => {\n const { client } = useChatClient();\n const [status, setStatus] = useState<RecoveryPinStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [recoveryStatus, setRecoveryStatus] = useState<RecoveryStatusInfo | null>(null);\n const [hasRecoveryKey, setHasRecoveryKey] = useState(() => {\n try {\n return !!requireEncryptionManager(client).hasRecoveryKey?.();\n } catch {\n return false;\n }\n });\n\n const refresh = useCallback(() => {\n void (async () => {\n try {\n const manager = requireEncryptionManager(client);\n const hasKey = !!manager.hasRecoveryKey?.();\n const nextStatus = manager.getRecoveryStatus ? await manager.getRecoveryStatus() : null;\n setHasRecoveryKey(hasKey);\n setRecoveryStatus(nextStatus);\n setStatus(nextStatus?.hasVault === false ? 'idle' : nextStatus?.unlocked ? 'ready' : 'locked');\n setError(null);\n } catch (err) {\n const nextError = err instanceof Error ? err : new Error(String(err));\n if (nextError.message.includes('Encryption manager is not initialized')) {\n setStatus('idle');\n setError(null);\n return;\n }\n setStatus('error');\n setError(nextError);\n }\n })();\n }, [client]);\n\n const run = useCallback(\n async <T>(fn: (manager: any) => Promise<T>): Promise<T> => {\n setStatus('working');\n setError(null);\n try {\n const manager = requireEncryptionManager(client);\n const result = await fn(manager);\n const hasKey = !!manager.hasRecoveryKey?.();\n const nextStatus = manager.getRecoveryStatus ? await manager.getRecoveryStatus() : null;\n setHasRecoveryKey(hasKey);\n setRecoveryStatus(nextStatus);\n setStatus(nextStatus?.hasVault === false ? 'idle' : nextStatus?.unlocked ? 'ready' : 'locked');\n return result;\n } catch (err) {\n const nextError = err instanceof Error ? err : new Error(String(err));\n setError(nextError);\n setStatus('error');\n throw nextError;\n }\n },\n [client],\n );\n\n const setupRecoveryPin = useCallback(\n async (pin: string): Promise<void> => {\n await run((manager) => manager.setupRecoveryPin(pin));\n },\n [run],\n );\n\n const unlockRecoveryVault = useCallback(\n async (pin: string): Promise<void> => {\n await run((manager) => manager.unlockRecoveryVault(pin));\n },\n [run],\n );\n\n const changeRecoveryPin = useCallback(\n async (oldPin: string, newPin: string): Promise<void> => {\n await run((manager) => manager.changeRecoveryPin(oldPin, newPin));\n },\n [run],\n );\n\n const changeUnlockedRecoveryPin = useCallback(\n async (newPin: string): Promise<void> => {\n await run((manager) => manager.changeUnlockedRecoveryPin(newPin));\n },\n [run],\n );\n\n const repairRecoveryChannel = useCallback(\n (channelType: string, channelId: string, options?: { mode?: RepairMode }): Promise<RepairResult> =>\n run((manager) => manager.repairRecoveryChannel(channelType, channelId, options)),\n [run],\n );\n\n const repairEncryptedChannel = useCallback(\n (\n channelType: string,\n channelId: string,\n options?: { mode?: EncryptedChannelRepairMode },\n ): Promise<EncryptedChannelRepairResult> =>\n run((manager) => manager.repairEncryptedChannel(channelType, channelId, options)),\n [run],\n );\n\n const restoreHistoricalMessages = useCallback(\n (\n channelType: string,\n channelId: string,\n options?: { fromEpoch?: number; toEpoch?: number },\n ): Promise<RecoveryRestoredMessage[]> =>\n run((manager) => manager.restoreHistoricalMessages(channelType, channelId, options)),\n [run],\n );\n\n const enqueueRestore = useCallback(\n (\n channelType: string,\n channelId: string,\n priority: 'active' | 'background' = 'active',\n options?: { fromEpoch?: number; toEpoch?: number },\n ): void => {\n try {\n const manager = requireEncryptionManager(client);\n manager.enqueueRestore?.(channelType, channelId, priority, options);\n refresh();\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setStatus('error');\n }\n },\n [client, refresh],\n );\n\n const loadRestoreProgress = useCallback(\n async (channelType: string, channelId: string): Promise<RestoreProgressRecord | null> => {\n try {\n const manager = requireEncryptionManager(client);\n return manager.getRestoreProgress ? await manager.getRestoreProgress(channelType, channelId) : null;\n } catch (err) {\n const nextError = err instanceof Error ? err : new Error(String(err));\n if (!nextError.message.includes('Encryption manager is not initialized')) {\n setError(nextError);\n }\n return null;\n }\n },\n [client],\n );\n\n useEffect(() => {\n const eventClient = client as any;\n if (!eventClient?.on) return;\n const progressSub = eventClient.on('e2ee.restore_progress' as any, refresh);\n const bootstrapSub = eventClient.on('e2ee.bootstrap_progress' as any, refresh);\n const initSub = eventClient.on('e2ee.initialized' as any, refresh);\n return () => {\n progressSub?.unsubscribe?.();\n bootstrapSub?.unsubscribe?.();\n initSub?.unsubscribe?.();\n };\n }, [client, refresh]);\n\n useEffect(() => {\n const eventClient = client as any;\n if (!eventClient || eventClient.encryptionManager?.initialized) return;\n const interval = setInterval(() => {\n refresh();\n if (eventClient.encryptionManager?.initialized) clearInterval(interval);\n }, 500);\n return () => clearInterval(interval);\n }, [client, refresh]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return useMemo(\n () => ({\n status,\n error,\n hasRecoveryKey,\n recoveryStatus,\n setupRecoveryPin,\n unlockRecoveryVault,\n changeRecoveryPin,\n changeUnlockedRecoveryPin,\n repairRecoveryChannel,\n repairEncryptedChannel,\n enqueueRestore,\n loadRestoreProgress,\n restoreHistoricalMessages,\n refresh,\n }),\n [\n status,\n error,\n hasRecoveryKey,\n recoveryStatus,\n setupRecoveryPin,\n unlockRecoveryVault,\n changeRecoveryPin,\n changeUnlockedRecoveryPin,\n repairRecoveryChannel,\n repairEncryptedChannel,\n enqueueRestore,\n loadRestoreProgress,\n restoreHistoricalMessages,\n refresh,\n ],\n );\n};\n","import React, { useState, useCallback, useRef, useEffect } from 'react';\nimport { Virtualizer as _Virtualizer } from 'virtua';\nconst Virtualizer = _Virtualizer as any;\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { usePreviewState } from '../../hooks/usePreviewState';\nimport { Avatar } from '../Avatar';\nimport { DefaultChannelInfoTabHeader } from './ChannelInfoTabs';\nimport { useChannelInfoTabs } from './useChannelInfoTabs';\nimport { AddMemberModal } from './AddMemberModal';\nimport { EditChannelModal } from './EditChannelModal';\nimport { TopicModal } from '../TopicModal';\nimport { MessageSearchPanel } from './MessageSearchPanel';\nimport { ChannelSettingsPanel } from './ChannelSettingsPanel';\nimport { MediaLightbox } from '../MediaLightbox';\nimport { PENDING_STYLE, READY_STYLE } from './utils';\nimport type {\n ChannelInfoProps,\n ChannelInfoHeaderProps,\n ChannelInfoCoverProps,\n ChannelInfoActionsProps,\n} from '../../types';\nimport { useChannelMembers, useChannelProfile } from '../../hooks/useChannelData';\nimport { isGroupChannel, isTopicChannel } from '../../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../../channelRoleUtils';\n\nconst MemoizedVirtualizer = React.memo(({ scrollRef, startMargin, data, renderItem, overscan = 10 }: any) => (\n <Virtualizer scrollRef={scrollRef} startMargin={startMargin} data={data} overscan={overscan}>\n {renderItem}\n </Virtualizer>\n));\n\nconst PinIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /></svg>);\nconst UnpinIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /><line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\" /></svg>);\nconst SearchIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line></svg>);\nconst SettingsIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"></circle><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path></svg>);\nconst DeleteIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"></polyline><path d=\"M19 6V20a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path></svg>);\nconst LeaveIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"></path><polyline points=\"16 17 21 12 16 7\"></polyline><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"></line></svg>);\nconst CloseTopicIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 10 0v4\" /></svg>);\nconst ReopenTopicIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 9.9-1\" /></svg>);\nconst BlockIcon = () => (<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" /></svg>);\n\nexport const DefaultChannelInfoHeader: React.FC<ChannelInfoHeaderProps> = React.memo(({ title, onClose }) => {\n return (\n <div className=\"ermis-channel-info__header\">\n <h3 className=\"ermis-channel-info__title\">{title}</h3>\n {onClose && (\n <button className=\"ermis-channel-info__close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n )}\n </div>\n );\n});\nDefaultChannelInfoHeader.displayName = 'DefaultChannelInfoHeader';\n\nexport const DefaultChannelInfoCover: React.FC<ChannelInfoCoverProps> = React.memo(({ channelName, channelImage, channelDescription, AvatarComponent, canEdit, onEditClick, isPublic, isTeamChannel, parentChannelName, isTopic }) => {\n const renderAvatar = () => {\n if (isTopic && channelImage && channelImage.startsWith('emoji://')) {\n const emoji = channelImage.replace('emoji://', '');\n return (\n <div className=\"ermis-channel-info__topic-emoji-avatar\">\n {emoji}\n </div>\n );\n }\n return <AvatarComponent image={channelImage} name={channelName} size={80} className=\"ermis-channel-info__avatar\" />;\n };\n\n return (\n <div className=\"ermis-channel-info__cover\">\n {renderAvatar()}\n <div className=\"ermis-channel-info__name-row\">\n <h2 className=\"ermis-channel-info__name\">{channelName}</h2>\n {canEdit && onEditClick && (\n <button className=\"ermis-channel-info__cover-edit-btn\" onClick={onEditClick} aria-label=\"Edit channel\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\n </svg>\n </button>\n )}\n </div>\n {parentChannelName && (\n <div className=\"ermis-channel-info__parent-name\">\n {parentChannelName}\n </div>\n )}\n {isTeamChannel && (\n <span className={`ermis-channel-info__type-badge ${isPublic ? 'ermis-channel-info__type-badge--public' : 'ermis-channel-info__type-badge--private'}`}>\n {isPublic ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n {isPublic ? 'Public' : 'Private'}\n </span>\n )}\n {channelDescription && (\n <p className=\"ermis-channel-info__description\">{channelDescription}</p>\n )}\n </div>\n );\n});\nDefaultChannelInfoCover.displayName = 'DefaultChannelInfoCover';\n\nexport const DefaultChannelInfoActions: React.FC<ChannelInfoActionsProps> = React.memo(({\n onSearchClick, onSettingsClick, onLeaveChannel, onDeleteChannel, onDeleteTopic, onTruncateChannel,\n onBlockUser, onUnblockUser, onPin, onUnpin, onCloseTopic, onReopenTopic,\n isTeamChannel, isTopic, isClosedTopic, isBlocked, isPinned, currentUserRole,\n searchLabel = 'Search', settingsLabel = 'Settings', deleteLabel = 'Delete', truncateLabel = 'Clear history', leaveLabel = 'Leave',\n blockLabel = 'Block', unblockLabel = 'Unblock', pinLabel = 'Pin', unpinLabel = 'Unpin',\n closeTopicLabel = 'Close Topic', reopenTopicLabel = 'Reopen Topic', deleteTopicLabel = 'Delete Topic'\n}) => {\n return (\n <div className=\"ermis-channel-info__actions\">\n <button className=\"ermis-channel-info__action-btn\" onClick={onSearchClick} disabled={isBlocked}>\n <div className=\"ermis-channel-info__action-icon\">\n <SearchIcon />\n </div>\n <span>{searchLabel}</span>\n </button>\n <button className=\"ermis-channel-info__action-btn\" onClick={isPinned ? onUnpin : onPin} disabled={isBlocked}>\n <div className=\"ermis-channel-info__action-icon\">\n {isPinned ? <UnpinIcon /> : <PinIcon />}\n </div>\n <span>{isPinned ? unpinLabel : pinLabel}</span>\n </button>\n {isTeamChannel && canManageChannel(currentUserRole) && (\n <button className=\"ermis-channel-info__action-btn\" onClick={onSettingsClick}>\n <div className=\"ermis-channel-info__action-icon\">\n <SettingsIcon />\n </div>\n <span>{settingsLabel}</span>\n </button>\n )}\n {isTeamChannel && (\n currentUserRole === CHANNEL_ROLES.OWNER ? (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onDeleteChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <DeleteIcon />\n </div>\n <span>{deleteLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onLeaveChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <LeaveIcon />\n </div>\n <span>{leaveLabel}</span>\n </button>\n )\n )}\n {/* Topics: Close/Reopen Topic for owner/moder */}\n {isTopic && canManageChannel(currentUserRole) && (\n isClosedTopic ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onReopenTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <ReopenTopicIcon />\n </div>\n <span>{reopenTopicLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onCloseTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <CloseTopicIcon />\n </div>\n <span>{closeTopicLabel}</span>\n </button>\n )\n )}\n {/* Topics: Delete Topic for owner */}\n {isTopic && currentUserRole === CHANNEL_ROLES.OWNER && onDeleteTopic && (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onDeleteTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <DeleteIcon />\n </div>\n <span>{deleteTopicLabel}</span>\n </button>\n )}\n {/* Block/Unblock & Truncate — messaging (1-1) channels only */}\n {!isTeamChannel && !isTopic && (\n <>\n {onTruncateChannel && (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onTruncateChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <DeleteIcon />\n </div>\n <span>{truncateLabel}</span>\n </button>\n )}\n {isBlocked ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onUnblockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <BlockIcon />\n </div>\n <span>{unblockLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onBlockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <BlockIcon />\n </div>\n <span>{blockLabel}</span>\n </button>\n )}\n </>\n )}\n </div>\n );\n});\nDefaultChannelInfoActions.displayName = 'DefaultChannelInfoActions';\n\nexport const ChannelInfo: React.FC<ChannelInfoProps> = React.memo((props) => {\n const {\n channel: channelProp,\n className = '',\n AvatarComponent = Avatar,\n onClose,\n title: titleProp,\n isVisible = true,\n HeaderComponent = DefaultChannelInfoHeader,\n CoverComponent = DefaultChannelInfoCover,\n ActionsComponent = DefaultChannelInfoActions,\n TabHeaderComponent = DefaultChannelInfoTabHeader,\n AddMemberModalComponent,\n EditChannelModalComponent,\n EditTopicModalComponent,\n actionsSearchLabel,\n actionsSettingsLabel,\n actionsDeleteLabel,\n actionsTruncateLabel,\n actionsLeaveLabel,\n actionsCreateTopicLabel,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n onSearchClick,\n onLeaveChannel: onLeaveChannelProp,\n onDeleteChannel: onDeleteChannelProp,\n onTruncateChannel: onTruncateChannelProp,\n onDeleteTopic: onDeleteTopicProp,\n onCreateTopic: onCreateTopicProp,\n onAddMemberClick,\n onRemoveMember: onRemoveMemberProp,\n onBanMember: onBanMemberProp,\n onUnbanMember: onUnbanMemberProp,\n onPromoteMember: onPromoteMemberProp,\n onDemoteMember: onDemoteMemberProp,\n onPinChannel: onPinChannelProp,\n onUnpinChannel: onUnpinChannelProp,\n // Add Member customization\n addMemberModalTitle,\n addMemberSearchPlaceholder,\n addMemberLoadingText,\n addMemberEmptyText,\n addMemberAddLabel,\n addMemberAddingLabel,\n addMemberAddedLabel,\n addMemberButtonLabel,\n MessageSearchPanelComponent,\n ChannelSettingsPanelComponent,\n AddMemberButtonComponent,\n // Edit Channel customization\n onEditChannel: onEditChannelProp,\n editChannelModalTitle,\n editChannelNameLabel,\n editChannelDescriptionLabel,\n editChannelNamePlaceholder,\n editChannelDescriptionPlaceholder,\n editChannelPublicLabel,\n editChannelSaveLabel,\n editChannelCancelLabel,\n editChannelSavingLabel,\n editChannelChangeAvatarLabel,\n editChannelImageAccept,\n editChannelMaxImageSize,\n editChannelMaxImageSizeError,\n // Block/Unblock customization (messaging channels)\n onBlockUser: onBlockUserProp,\n onUnblockUser: onUnblockUserProp,\n actionsBlockLabel,\n actionsUnblockLabel,\n actionsPinLabel,\n actionsUnpinLabel,\n actionsPinTopicLabel,\n actionsUnpinTopicLabel,\n actionsCloseTopicLabel,\n actionsReopenTopicLabel,\n actionsDeleteTopicLabel,\n // Settings panel customizations\n settingsWorkspaceTopicsTitle,\n settingsTopicsFeatureName,\n settingsTopicsFeatureDescription,\n roleLabels,\n } = props;\n\n const { activeChannel, client } = useChatClient();\n const scrollContainerRef = useRef<HTMLDivElement | null>(null);\n\n const channel = channelProp || activeChannel;\n const { isBanned } = useBannedState(channel, client?.userID);\n const { isBlocked } = useBlockedState(channel, client?.userID);\n const { isPreviewMode } = usePreviewState(channel, client?.userID);\n\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const isTeamChannel = isGroupChannel(channel);\n const isTopic = isTopicChannel(channel);\n const isClosedTopic = channel?.data?.is_closed_topic === true;\n const title = titleProp !== undefined ? titleProp : (isTopic ? 'Topic Info' : 'Channel Info');\n\n const parentCid = channel?.data?.parent_cid as string | undefined;\n const parentChannel = parentCid && client ? client.activeChannels[parentCid] : undefined;\n let parentChannelName = parentChannel?.data?.name || (parentCid ? 'Unknown' : undefined);\n const e2eeChannel = parentChannel || channel;\n const isE2ee = Boolean(e2eeChannel?.data?.mls_enabled);\n const [isRotatingKey, setIsRotatingKey] = useState(false);\n const [isEnablingE2ee, setIsEnablingE2ee] = useState(false);\n const encryptionEpoch =\n isE2ee && e2eeChannel?.cid && typeof client?.encryptionManager?.getEpoch === 'function'\n ? client.encryptionManager.getEpoch(e2eeChannel.cid)\n : undefined;\n\n const handleDeleteChannel = useCallback(async () => {\n if (onDeleteChannelProp) return onDeleteChannelProp();\n if (!channel) return;\n try {\n await channel.delete();\n } catch (e) {\n console.error(\"Error deleting channel\", e);\n }\n }, [channel, onDeleteChannelProp]);\n\n const handleLeaveChannel = useCallback(async () => {\n if (onLeaveChannelProp) return onLeaveChannelProp();\n if (!channel || !currentUserId) return;\n try {\n if (channel.data?.mls_enabled) {\n await channel.leaveChannelE2ee(currentUserId);\n } else {\n await channel.removeMembers([currentUserId]);\n }\n } catch (e) {\n console.error(\"Error leaving channel\", e);\n throw e;\n }\n }, [channel, currentUserId, onLeaveChannelProp]);\n\n const handleRemoveMember = useCallback(async (memberId: string) => {\n if (onRemoveMemberProp) return onRemoveMemberProp(memberId);\n if (!channel) return;\n try {\n const encryptionManager = channel.getClient().encryptionManager;\n if (channel.data?.mls_enabled) {\n if (!encryptionManager?.initialized || !channel.id || !channel.cid) {\n throw new Error('[E2EE] Cannot remove member from E2EE channel before encryption is initialized');\n }\n await encryptionManager.evictMember(channel.type, channel.id, channel.cid, memberId);\n } else {\n await channel.removeMembers([memberId]);\n }\n } catch (e) {\n console.error(\"Error removing member\", e);\n throw e;\n }\n }, [channel, onRemoveMemberProp]);\n\n const handleBanMember = useCallback(async (memberId: string) => {\n if (onBanMemberProp) return onBanMemberProp(memberId);\n if (!channel) return;\n try { await channel.banMembers([memberId]); } catch (e) { console.error(\"Error banning member\", e); }\n }, [channel, onBanMemberProp]);\n\n const handleUnbanMember = useCallback(async (memberId: string) => {\n if (onUnbanMemberProp) return onUnbanMemberProp(memberId);\n if (!channel) return;\n try { await channel.unbanMembers([memberId]); } catch (e) { console.error(\"Error unbanning member\", e); }\n }, [channel, onUnbanMemberProp]);\n\n const handlePromoteMember = useCallback(async (memberId: string) => {\n if (onPromoteMemberProp) return onPromoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.addModerators([memberId]); } catch (e) { console.error(\"Error promoting member\", e); }\n }, [channel, onPromoteMemberProp]);\n\n const handleDemoteMember = useCallback(async (memberId: string) => {\n if (onDemoteMemberProp) return onDemoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.demoteModerators([memberId]); } catch (e) { console.error(\"Error demoting member\", e); }\n }, [channel, onDemoteMemberProp]);\n\n const handleBlockUser = useCallback(async () => {\n if (onBlockUserProp) return onBlockUserProp();\n if (!channel) return;\n try { await channel.blockUser(); } catch (e) { console.error('Error blocking user', e); }\n }, [channel, onBlockUserProp]);\n\n const handleUnblockUser = useCallback(async () => {\n if (onUnblockUserProp) return onUnblockUserProp();\n if (!channel) return;\n try { await channel.unblockUser(); } catch (e) { console.error('Error unblocking user', e); }\n }, [channel, onUnblockUserProp]);\n\n const handleRotateKey = useCallback(async () => {\n if (!e2eeChannel?.cid || !client?.encryptionManager?.initialized || parentCid) return;\n try {\n setIsRotatingKey(true);\n await client.encryptionManager.keyRotation(e2eeChannel.cid);\n } catch (e) {\n console.error('Error rotating E2EE key', e);\n } finally {\n setIsRotatingKey(false);\n }\n }, [client, e2eeChannel?.cid, parentCid]);\n\n const handleEnableE2ee = useCallback(async () => {\n if (!channel?.id || !channel?.cid || !client?.encryptionManager?.initialized || parentCid || isE2ee) return;\n try {\n setIsEnablingE2ee(true);\n const memberUserIds = Object.keys(channel.state?.members || {});\n const recoveryPolicy = (channel.data as any)?.e2ee_recovery_policy || 'member_assisted';\n const result = await client.encryptionManager.enableE2ee(\n channel.type,\n channel.id,\n channel.cid,\n memberUserIds,\n recoveryPolicy,\n );\n channel.data = {\n ...channel.data,\n mls_enabled: true,\n e2ee_recovery_policy:\n result?.channel?.e2ee_recovery_policy || result?.e2ee_recovery_policy || recoveryPolicy,\n mls_enabled_at: result?.channel?.mls_enabled_at || result?.mls_enabled_at || new Date().toISOString(),\n mls_epoch: result?.channel?.mls_epoch ?? result?.epoch ?? channel.data?.mls_epoch,\n } as any;\n channel.getClient().dispatchEvent({\n type: 'channel.updated',\n cid: channel.cid,\n channel_type: channel.type,\n channel_id: channel.id,\n channel: channel.data,\n user: channel.getClient().user,\n } as any);\n } catch (e) {\n console.error('Error enabling E2EE', e);\n } finally {\n setIsEnablingE2ee(false);\n }\n }, [channel, client, parentCid, isE2ee]);\n\n const handlePinChannel = useCallback(async () => {\n if (onPinChannelProp) return onPinChannelProp();\n if (!channel) return;\n try { await channel.pin(); } catch (e) { console.error('Error pinning channel', e); }\n }, [channel, onPinChannelProp]);\n\n const handleUnpinChannel = useCallback(async () => {\n if (onUnpinChannelProp) return onUnpinChannelProp();\n if (!channel) return;\n try { await channel.unpin(); } catch (e) { console.error('Error unpanning channel', e); }\n }, [channel, onUnpinChannelProp]);\n\n const handleCloseTopic = useCallback(async () => {\n if (!channel || !parentChannel) return;\n try { await parentChannel.closeTopic(channel.cid); } catch (e) { console.error('Error closing topic', e); }\n }, [channel, parentChannel]);\n\n const handleReopenTopic = useCallback(async () => {\n if (!channel || !parentChannel) return;\n try { await parentChannel.reopenTopic(channel.cid); } catch (e) { console.error('Error reopening topic', e); }\n }, [channel, parentChannel]);\n\n const handleDeleteTopic = useCallback(async () => {\n if (onDeleteTopicProp) return onDeleteTopicProp(channel as any);\n if (!channel) return;\n try { await channel.delete(); } catch (e) { console.error('Error deleting topic', e); }\n }, [channel, onDeleteTopicProp]);\n\n const { members } = useChannelMembers(channel);\n const { channelName: profileChannelName, channelImage, channelDescription, isPinned } = useChannelProfile(channel);\n\n let finalChannelName = profileChannelName;\n let finalParentChannelName = parentChannelName;\n\n // If this is the proxy 'general' channel, show the team name as the main name and hide the parent name.\n if (isGroupChannel(channel) && channel?.data?.name === 'general' && channel.cid) {\n const realChannelName = client?.activeChannels[channel.cid]?.data?.name;\n if (realChannelName && realChannelName !== 'general') {\n finalChannelName = realChannelName;\n finalParentChannelName = undefined;\n }\n }\n\n const [showAddMemberModal, setShowAddMemberModal] = useState(false);\n const [showEditChannelModal, setShowEditChannelModal] = useState(false);\n const [showEditTopicModal, setShowEditTopicModal] = useState(false);\n const [showSearchPanel, setShowSearchPanel] = useState(false);\n const [showSettingsPanel, setShowSettingsPanel] = useState(false);\n\n // Permission: only owner or moderator can edit channel info (banned users cannot)\n const canEditChannel = (isTeamChannel || isTopic) && !isBanned && canManageChannel(currentUserRole);\n\n const handleEditChannelClick = useCallback(() => {\n if (isTopic) {\n setShowEditTopicModal(true);\n } else {\n setShowEditChannelModal(true);\n }\n }, [isTopic]);\n\n const handleAddMemberClick = useCallback(() => {\n if (onAddMemberClick) return onAddMemberClick();\n setShowAddMemberModal(true);\n }, [onAddMemberClick]);\n\n // virtualizer anchors for page-level virtualization\n const virtualizerAnchorRef = useRef<HTMLDivElement | null>(null);\n const [startMargin, setStartMargin] = useState(0);\n\n // Use the headless tabs hook\n const tabs = useChannelInfoTabs({\n channel: channel as any,\n members: members as any,\n AvatarComponent,\n currentUserId,\n currentUserRole,\n onAddMemberClick: isTeamChannel && !isPreviewMode ? handleAddMemberClick : undefined,\n onRemoveMember: handleRemoveMember,\n onBanMember: handleBanMember,\n onUnbanMember: handleUnbanMember,\n onPromoteMember: handlePromoteMember,\n onDemoteMember: handleDemoteMember,\n addMemberButtonLabel,\n AddMemberButtonComponent,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n isVisible,\n isPreviewMode,\n roleLabels,\n });\n\n // Calculate startMargin for Virtualizer (distance from body top to virtualizer anchor)\n useEffect(() => {\n const body = scrollContainerRef.current;\n const anchor = virtualizerAnchorRef.current;\n if (!body || !anchor) return;\n const bodyRect = body.getBoundingClientRect();\n const anchorRect = anchor.getBoundingClientRect();\n setStartMargin(anchorRect.top - bodyRect.top + body.scrollTop);\n }, [isVisible, tabs.activeTab, isBanned, isPreviewMode]);\n\n if (!channel) return null;\n\n return (\n <div className={`ermis-channel-info ${className}`.trim()}>\n <HeaderComponent title={title} onClose={onClose} />\n <div className=\"ermis-channel-info__body\" ref={scrollContainerRef}>\n <CoverComponent\n channelName={finalChannelName}\n channelImage={channelImage}\n channelDescription={channelDescription}\n AvatarComponent={AvatarComponent}\n canEdit={canEditChannel}\n onEditClick={handleEditChannelClick}\n isPublic={Boolean(channel?.data?.public)}\n isTeamChannel={isTeamChannel}\n parentChannelName={finalParentChannelName}\n isTopic={isTopic}\n isE2ee={isE2ee}\n encryptionEpoch={encryptionEpoch}\n />\n\n {isBanned && (\n <div className=\"ermis-channel-info__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\"></line>\n </svg>\n <span className=\"ermis-channel-info__banned-banner-text\">You have been banned from this channel</span>\n </div>\n )}\n {!isBanned && isPreviewMode && (\n <div className=\"ermis-channel-info__preview-actions\">\n <button\n className=\"ermis-channel-info__join-btn\"\n onClick={() => channel?.acceptInvite('join').catch(e => console.error('Failed to join public channel', e))}\n >\n Join Channel\n </button>\n </div>\n )}\n {!isBanned && (\n <>\n {!isPreviewMode && (\n <ActionsComponent\n channel={channel}\n onSearchClick={() => setShowSearchPanel(true)}\n onSettingsClick={() => setShowSettingsPanel(true)}\n onLeaveChannel={handleLeaveChannel}\n onDeleteChannel={handleDeleteChannel}\n onTruncateChannel={onTruncateChannelProp ? () => onTruncateChannelProp(channel) : undefined}\n onBlockUser={handleBlockUser}\n onUnblockUser={handleUnblockUser}\n onPin={handlePinChannel}\n onUnpin={handleUnpinChannel}\n onCloseTopic={handleCloseTopic}\n onReopenTopic={handleReopenTopic}\n onDeleteTopic={handleDeleteTopic}\n onCreateTopic={onCreateTopicProp ? () => onCreateTopicProp(channel) : undefined}\n isTeamChannel={isTeamChannel}\n isTopic={isTopic}\n isClosedTopic={isClosedTopic}\n isBlocked={isBlocked}\n isPinned={isPinned}\n topicsEnabled={channel?.data?.topics_enabled === true}\n currentUserRole={currentUserRole}\n isE2ee={isE2ee}\n encryptionInitialized={Boolean(client?.encryptionManager?.initialized)}\n encryptionEpoch={encryptionEpoch}\n onRotateKey={!isTopic && isE2ee && canManageChannel(currentUserRole) ? handleRotateKey : undefined}\n rotateKeyDisabled={isRotatingKey || isBlocked || isClosedTopic}\n onEnableE2ee={!isTopic && !isE2ee && currentUserRole === CHANNEL_ROLES.OWNER ? handleEnableE2ee : undefined}\n enableE2eeDisabled={isEnablingE2ee || isBlocked || isClosedTopic || !client?.encryptionManager?.initialized}\n searchLabel={actionsSearchLabel}\n settingsLabel={actionsSettingsLabel}\n deleteLabel={actionsDeleteLabel}\n truncateLabel={actionsTruncateLabel}\n leaveLabel={actionsLeaveLabel}\n blockLabel={actionsBlockLabel}\n unblockLabel={actionsUnblockLabel}\n pinLabel={isTopic ? (actionsPinTopicLabel || 'Pin topic') : (actionsPinLabel || 'Pin channel')}\n unpinLabel={isTopic ? (actionsUnpinTopicLabel || 'Unpin topic') : (actionsUnpinLabel || 'Unpin channel')}\n closeTopicLabel={actionsCloseTopicLabel}\n reopenTopicLabel={actionsReopenTopicLabel}\n deleteTopicLabel={actionsDeleteTopicLabel}\n createTopicLabel={actionsCreateTopicLabel}\n />\n )}\n\n <TabHeaderComponent\n activeTab={tabs.activeTab}\n onTabChange={tabs.handleTabChange}\n availableTabs={tabs.availableTabs}\n tabCounts={{} as any}\n />\n\n <div\n ref={virtualizerAnchorRef}\n className=\"ermis-channel-info__media-content\"\n style={tabs.isPending ? PENDING_STYLE : READY_STYLE}\n >\n {tabs.isPending || (tabs.loading && tabs.contentTab !== 'members') ? (\n <tabs.Loading tab={tabs.activeTab} />\n ) : tabs.isTabEmpty ? (\n <tabs.EmptyState label={tabs.emptyLabel} />\n ) : (\n <MemoizedVirtualizer \n scrollRef={scrollContainerRef} \n startMargin={startMargin} \n data={tabs.vlistData} \n renderItem={tabs.renderVlistItem} \n />\n )}\n </div>\n\n {/* Media Lightbox */}\n {tabs.lightboxItems.length > 0 && (\n <MediaLightbox\n items={tabs.lightboxItems}\n initialIndex={tabs.lightboxIndex}\n isOpen={tabs.lightboxOpen}\n onClose={tabs.closeLightbox}\n />\n )}\n\n {showAddMemberModal && (() => {\n const ModalComp = AddMemberModalComponent || AddMemberModal;\n return (\n <ModalComp\n channel={channel}\n currentMembers={members as any}\n onClose={() => setShowAddMemberModal(false)}\n AvatarComponent={AvatarComponent}\n title={addMemberModalTitle}\n searchPlaceholder={addMemberSearchPlaceholder}\n loadingText={addMemberLoadingText}\n emptyText={addMemberEmptyText}\n addLabel={addMemberAddLabel}\n />\n );\n })()}\n\n {showEditChannelModal && (() => {\n const ModalComp = EditChannelModalComponent || EditChannelModal;\n return (\n <ModalComp\n channel={channel}\n onClose={() => setShowEditChannelModal(false)}\n onSave={onEditChannelProp}\n AvatarComponent={AvatarComponent}\n title={editChannelModalTitle}\n nameLabel={editChannelNameLabel}\n descriptionLabel={editChannelDescriptionLabel}\n namePlaceholder={editChannelNamePlaceholder}\n descriptionPlaceholder={editChannelDescriptionPlaceholder}\n publicLabel={editChannelPublicLabel}\n saveLabel={editChannelSaveLabel}\n cancelLabel={editChannelCancelLabel}\n savingLabel={editChannelSavingLabel}\n changeAvatarLabel={editChannelChangeAvatarLabel}\n imageAccept={editChannelImageAccept}\n maxImageSize={editChannelMaxImageSize}\n maxImageSizeError={editChannelMaxImageSizeError}\n />\n );\n })()}\n\n {showEditTopicModal && (() => {\n const ModalComp = EditTopicModalComponent || TopicModal;\n return (\n <ModalComp\n isOpen={true}\n onClose={() => setShowEditTopicModal(false)}\n topic={channel}\n />\n );\n })()}\n </>\n )}\n </div>\n\n {/* Search Panel — slides over entire ChannelInfo body */}\n {channel && showSearchPanel && (() => {\n const SearchPanel = MessageSearchPanelComponent || MessageSearchPanel;\n return (\n <SearchPanel\n isOpen={showSearchPanel}\n onClose={() => setShowSearchPanel(false)}\n channel={channel}\n AvatarComponent={AvatarComponent}\n />\n );\n })()}\n\n {/* Settings Panel — slides over entire ChannelInfo body */}\n {channel && showSettingsPanel && (() => {\n const SettingsPanel = ChannelSettingsPanelComponent || ChannelSettingsPanel;\n return (\n <SettingsPanel\n isOpen={showSettingsPanel}\n onClose={() => setShowSettingsPanel(false)}\n channel={channel}\n workspaceTopicsTitle={settingsWorkspaceTopicsTitle}\n topicsFeatureName={settingsTopicsFeatureName}\n topicsFeatureDescription={settingsTopicsFeatureDescription}\n />\n );\n })()}\n </div>\n );\n});\n\nChannelInfo.displayName = 'ChannelInfo';\n","import React from 'react';\nimport { VList as _VList } from 'virtua';\nconst VList = _VList as any;\nimport { PENDING_STYLE, READY_STYLE } from './utils';\nimport { MediaLightbox } from '../MediaLightbox';\nimport type { ChannelInfoTabsProps, ChannelInfoTabHeaderProps } from '../../types';\nimport { useChannelInfoTabs } from './useChannelInfoTabs';\n\n/* =============================================\n Component: DefaultChannelInfoTabHeader\n Renders the tab buttons row.\n ============================================= */\n\nexport const DefaultChannelInfoTabHeader: React.FC<ChannelInfoTabHeaderProps> = React.memo(({\n activeTab,\n onTabChange,\n availableTabs,\n}) => {\n return (\n <div className=\"ermis-channel-info__media-tabs\">\n {availableTabs.map(tab => (\n <button\n key={tab}\n className={`ermis-channel-info__media-tab ${activeTab === tab ? 'ermis-channel-info__media-tab--active' : ''}`}\n onClick={() => onTabChange(tab)}\n >\n <span className=\"ermis-channel-info__media-tab-label\">\n {tab.charAt(0).toUpperCase() + tab.slice(1)}\n </span>\n </button>\n ))}\n </div>\n );\n});\nDefaultChannelInfoTabHeader.displayName = 'DefaultChannelInfoTabHeader';\n\n/* =============================================\n Component: DefaultChannelInfoTabs\n Self-contained tabs component with internal VList.\n Kept for backward compatibility.\n ============================================= */\n\nexport const DefaultChannelInfoTabs: React.FC<ChannelInfoTabsProps> = React.memo((props) => {\n const {\n TabHeaderComponent,\n } = props;\n\n const tabs = useChannelInfoTabs(props);\n const TabHeader = TabHeaderComponent || DefaultChannelInfoTabHeader;\n\n return (\n <div className=\"ermis-channel-info__section ermis-channel-info__media-section\">\n <TabHeader\n activeTab={tabs.activeTab}\n onTabChange={tabs.handleTabChange}\n availableTabs={tabs.availableTabs}\n tabCounts={{} as any}\n />\n\n <div\n className=\"ermis-channel-info__media-content\"\n style={tabs.isPending ? PENDING_STYLE : READY_STYLE}\n >\n {tabs.isPending || (tabs.loading && tabs.contentTab !== 'members') ? <tabs.Loading /> : tabs.isTabEmpty ? <tabs.EmptyState label={tabs.emptyLabel} /> : (\n <VList data={tabs.vlistData}>\n {tabs.renderVlistItem}\n </VList>\n )}\n </div>\n\n {/* Media Lightbox */}\n {tabs.lightboxItems.length > 0 && (\n <MediaLightbox\n items={tabs.lightboxItems}\n initialIndex={tabs.lightboxIndex}\n isOpen={tabs.lightboxOpen}\n onClose={tabs.closeLightbox}\n />\n )}\n </div>\n );\n});\nDefaultChannelInfoTabs.displayName = 'DefaultChannelInfoTabs';\n","import React, { useState, useEffect, useMemo, useCallback, startTransition, useRef } from 'react';\nimport { ROLE_WEIGHTS, MESSAGING_TABS, ALL_TABS } from './utils';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { MediaGridItem, MediaRow } from './MediaGridItem';\nimport { LinkListItem } from './LinkListItem';\nimport { FileListItem } from './FileListItem';\nimport { MemberListItem } from './MemberListItem';\nimport { TabEmptyState, TabLoadingState } from './States';\nimport { useDownloadHandler } from '../../hooks/useDownloadHandler';\nimport type { ChannelInfoTabsProps, MediaTab, AttachmentItem, MediaLightboxItem } from '../../types';\nimport { isDirectChannel } from '../../channelTypeUtils';\nimport {\n CHANNEL_ROLES,\n canRemoveTargetMember,\n canBanTargetMember,\n canPromoteTargetMember,\n canDemoteTargetMember,\n} from '../../channelRoleUtils';\n\nexport const useChannelInfoTabs = (props: ChannelInfoTabsProps) => {\n const {\n channel,\n members,\n AvatarComponent,\n currentUserId,\n currentUserRole,\n onAddMemberClick,\n onRemoveMember,\n onBanMember,\n onUnbanMember,\n onPromoteMember,\n onDemoteMember,\n addMemberButtonLabel = 'Add Member',\n AddMemberButtonComponent,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n isVisible = true,\n isPreviewMode = false,\n } = props;\n\n const isMessaging = isDirectChannel(channel);\n const isTopic = Boolean(channel?.data?.parent_cid);\n\n const { isBanned } = useBannedState(channel, currentUserId);\n const { isBlocked } = useBlockedState(channel, currentUserId);\n\n const availableTabs: MediaTab[] = useMemo(() => {\n let tabs = isMessaging ? MESSAGING_TABS : ALL_TABS;\n if (isTopic) {\n tabs = tabs.filter((t) => t !== 'members');\n }\n return tabs;\n }, [isMessaging, isTopic]);\n\n const [activeTab, setActiveTab] = useState<MediaTab>(availableTabs[0]);\n const [contentTab, setContentTab] = useState<MediaTab>(availableTabs[0]);\n const [isPending, setIsPending] = useState(false);\n\n const [attachmentsFetchedForCid, setAttachmentsFetchedForCid] = useState<string | null>(null);\n const lastFetchedCidRef = useRef<string | null>(null);\n const transitionRafRef = useRef<any>(null);\n\n const handleTabChange = useCallback(\n (tab: MediaTab) => {\n if (tab === activeTab) return;\n\n // 1. Instant UI update for the tab button\n setActiveTab(tab);\n\n if (transitionRafRef.current) clearTimeout(transitionRafRef.current);\n\n // Check if data is already available for this channel\n const hasData = tab === 'members' || attachmentsFetchedForCid === channel?.cid;\n\n if (hasData) {\n // If data exists, switch content immediately without loading state\n setContentTab(tab);\n setIsPending(false);\n } else {\n // If no data, use isPending to show Skeleton while waiting for API\n setIsPending(true);\n transitionRafRef.current = setTimeout(() => {\n setContentTab(tab);\n setIsPending(false);\n setAttachmentsFetchedForCid((prev) => prev || channel?.cid || null);\n }, 350);\n }\n },\n [activeTab, channel?.cid, attachmentsFetchedForCid],\n );\n\n // Reset tab when user switches channels\n useEffect(() => {\n if (transitionRafRef.current) clearTimeout(transitionRafRef.current);\n setActiveTab(availableTabs[0]);\n setContentTab(availableTabs[0]);\n setIsPending(false);\n setAttachmentsFetchedForCid(null);\n setAllAttachments([]);\n lastFetchedCidRef.current = null;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel?.cid, availableTabs]);\n\n // Auto-trigger fetch for channels where default tab needs attachment data\n useEffect(() => {\n if (!isVisible) return;\n if (availableTabs[0] === 'members') return;\n const rafId = requestAnimationFrame(() => {\n setAttachmentsFetchedForCid(channel?.cid || null);\n });\n return () => cancelAnimationFrame(rafId);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel?.cid, availableTabs, isVisible]);\n\n // Resolve sub-components with defaults\n const MemberItem = MemberItemComponent || MemberListItem;\n const MediaItem = MediaItemComponent || MediaGridItem;\n const LinkItem = LinkItemComponent || LinkListItem;\n const FileItem = FileItemComponent || FileListItem;\n const EmptyState = EmptyStateComponent || TabEmptyState;\n const Loading = LoadingComponent || TabLoadingState;\n\n const [allAttachments, setAllAttachments] = useState<AttachmentItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [refreshAttachmentsCount, setRefreshAttachmentsCount] = useState(0);\n\n const forceRefreshAttachments = useCallback(() => {\n lastFetchedCidRef.current = null;\n setRefreshAttachmentsCount((c) => c + 1);\n }, []);\n\n const sortedMembers = useMemo(() => {\n return [...members].sort((a, b) => {\n const aWeight = ROLE_WEIGHTS[a.channel_role || CHANNEL_ROLES.MEMBER] || 0;\n const bWeight = ROLE_WEIGHTS[b.channel_role || CHANNEL_ROLES.MEMBER] || 0;\n return bWeight - aWeight;\n });\n }, [members]);\n\n // Categorize attachments by type\n const mediaItems = useMemo(\n () => allAttachments.filter((a) => a.attachment_type === 'image' || a.attachment_type === 'video'),\n [allAttachments],\n );\n\n const linkItems = useMemo(() => allAttachments.filter((a) => a.attachment_type === 'linkPreview'), [allAttachments]);\n\n const fileItems = useMemo(\n () => allAttachments.filter((a) => a.attachment_type === 'file' || a.attachment_type === 'voiceRecording'),\n [allAttachments],\n );\n\n useEffect(() => {\n if (!isVisible) return;\n if (!attachmentsFetchedForCid || attachmentsFetchedForCid !== channel?.cid) {\n setLoading(false);\n return;\n }\n if (lastFetchedCidRef.current === channel?.cid) return;\n\n let active = true;\n\n if (isBanned || isBlocked || isPreviewMode) {\n setAllAttachments([]);\n setLoading(false);\n return;\n }\n\n const fetchMedia = async () => {\n setLoading(true);\n try {\n const response: any = await channel.queryAttachmentMessages();\n if (active) {\n const items = response?.attachments || [];\n startTransition(() => {\n setAllAttachments(items);\n });\n lastFetchedCidRef.current = channel?.cid || null;\n }\n } catch (err) {\n console.error('Failed to query media for channel info', err);\n if (active) setAllAttachments([]);\n } finally {\n if (active) setLoading(false);\n }\n };\n\n fetchMedia();\n return () => {\n active = false;\n };\n }, [channel, isBanned, isBlocked, isPreviewMode, attachmentsFetchedForCid, isVisible, refreshAttachmentsCount]);\n\n // Listen to realtime events to automatically refresh attachments\n useEffect(() => {\n if (!channel || !isVisible) return;\n\n const handleEvent = (event: any) => {\n if (event.message?.attachments && event.message.attachments.length > 0) {\n forceRefreshAttachments();\n }\n };\n\n channel.on('message.new', handleEvent);\n channel.on('message.deleted', handleEvent);\n channel.on('message.updated', handleEvent);\n\n return () => {\n channel.off('message.new', handleEvent);\n channel.off('message.deleted', handleEvent);\n channel.off('message.updated', handleEvent);\n };\n }, [channel, isVisible, forceRefreshAttachments]);\n\n const { downloadFile } = useDownloadHandler();\n\n const handleDownloadFile = useCallback(\n async (url: string, filename?: string) => {\n await downloadFile(url, filename);\n },\n [downloadFile],\n );\n\n // Lightbox state for media tab\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [lightboxIndex, setLightboxIndex] = useState(0);\n\n const lightboxItems = useMemo<MediaLightboxItem[]>(() => {\n return mediaItems\n .filter((item) => !item.e2ee_manifest && !item.e2ee_manifest_missing)\n .map((item) => ({\n type: (item.attachment_type === 'video' ? 'video' : 'image') as 'image' | 'video',\n src: item.url,\n alt: item.file_name,\n posterSrc: item.thumb_url || undefined,\n }));\n }, [mediaItems]);\n\n const handleMediaClick = useCallback(\n (url: string) => {\n const idx = mediaItems\n .filter((item) => !item.e2ee_manifest && !item.e2ee_manifest_missing)\n .findIndex((item) => item.url === url);\n if (idx >= 0) {\n setLightboxIndex(idx);\n setLightboxOpen(true);\n }\n },\n [mediaItems],\n );\n\n const closeLightbox = useCallback(() => {\n setLightboxOpen(false);\n }, []);\n\n // Group media into rows of 3 for grid layout inside VList\n const mediaRows = useMemo(() => {\n const rows: AttachmentItem[][] = [];\n for (let i = 0; i < mediaItems.length; i += 3) {\n rows.push(mediaItems.slice(i, i + 3));\n }\n return rows;\n }, [mediaItems]);\n\n // Build VList data array based on contentTab (deferred)\n const vlistData = useMemo(() => {\n switch (contentTab) {\n case 'members': {\n const items: any[] = [];\n if (onAddMemberClick) {\n items.push({ type: 'add-member' });\n }\n sortedMembers.forEach((member) => {\n items.push({ type: 'member', data: member });\n });\n return items;\n }\n case 'media':\n return mediaRows.map((row) => ({ type: 'media-row', data: row }));\n case 'links':\n return linkItems.map((item) => ({ type: 'link', data: item }));\n case 'files':\n return fileItems.map((item) => ({ type: 'file', data: item }));\n default:\n return [];\n }\n }, [contentTab, sortedMembers, mediaRows, mediaItems, linkItems, fileItems, onAddMemberClick]);\n\n // Render function for VList items\n const renderVlistItem = useCallback(\n (item: any, index: number) => {\n switch (item.type) {\n case 'add-member':\n if (AddMemberButtonComponent) {\n return (\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <AddMemberButtonComponent onClick={onAddMemberClick!} label={addMemberButtonLabel} />\n </div>\n );\n }\n return (\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <button className=\"ermis-channel-info__add-member-btn\" onClick={onAddMemberClick}>\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"></path>\n <circle cx=\"8.5\" cy=\"7\" r=\"4\"></circle>\n <line x1=\"20\" y1=\"8\" x2=\"20\" y2=\"14\"></line>\n <line x1=\"23\" y1=\"11\" x2=\"17\" y2=\"11\"></line>\n </svg>\n {addMemberButtonLabel}\n </button>\n </div>\n );\n case 'member': {\n const member = item.data;\n const role = member.channel_role || CHANNEL_ROLES.MEMBER;\n const isTargetRemovable = canRemoveTargetMember(currentUserRole, role);\n const canRemove = Boolean(isTargetRemovable && member.user_id !== currentUserId);\n const canBan = Boolean(\n canBanTargetMember(currentUserRole, role) && member.user_id !== currentUserId && !member.banned,\n );\n const canUnban = Boolean(\n canBanTargetMember(currentUserRole, role) && member.user_id !== currentUserId && member.banned,\n );\n const canPromote = canPromoteTargetMember(currentUserRole, role) && member.user_id !== currentUserId;\n const canDemote = canDemoteTargetMember(currentUserRole, role) && member.user_id !== currentUserId;\n\n return (\n <MemberItem\n key={member?.user_id || index}\n member={member}\n AvatarComponent={AvatarComponent}\n onRemove={onRemoveMember}\n canRemove={canRemove}\n onBan={onBanMember}\n canBan={canBan}\n onUnban={onUnbanMember}\n canUnban={canUnban}\n onPromote={onPromoteMember}\n canPromote={canPromote}\n onDemote={onDemoteMember}\n canDemote={canDemote}\n />\n );\n }\n case 'media-row':\n return (\n <MediaRow\n key={item.data[0]?.id || index}\n row={item.data}\n onClick={handleMediaClick}\n MediaItemComponent={MediaItem}\n />\n );\n case 'link':\n return <LinkItem key={item.data.id || index} item={item.data} />;\n case 'file':\n const fileItem = item.data as AttachmentItem;\n return (\n <FileItem\n key={fileItem.id || index}\n item={fileItem}\n onClick={(url: string) => handleDownloadFile(url, fileItem.file_name)}\n />\n );\n default:\n return null;\n }\n },\n [\n onAddMemberClick,\n AddMemberButtonComponent,\n addMemberButtonLabel,\n currentUserRole,\n currentUserId,\n AvatarComponent,\n onRemoveMember,\n onBanMember,\n onUnbanMember,\n onPromoteMember,\n onDemoteMember,\n handleMediaClick,\n MediaItem,\n handleDownloadFile,\n MemberItem,\n LinkItem,\n FileItem,\n ],\n );\n\n const isTabEmpty = vlistData.length === 0 && !(loading && contentTab !== 'members');\n const emptyLabel = contentTab === 'members' ? 'members' : contentTab;\n\n return {\n availableTabs,\n activeTab,\n contentTab,\n handleTabChange,\n isPending,\n loading,\n isTabEmpty,\n emptyLabel,\n vlistData,\n renderVlistItem,\n lightboxItems,\n lightboxOpen,\n lightboxIndex,\n handleMediaClick,\n closeLightbox,\n EmptyState,\n Loading,\n };\n};\n","import React, { useCallback, useEffect, useRef, useState, useMemo } from 'react';\nimport { preloadImage, isImagePreloaded } from '../../utils';\nimport type { AttachmentItem, MediaLightboxItem } from '../../types';\nimport { MediaLightbox } from '../MediaLightbox';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { E2EE_PREVIEW_MAX_CONCURRENT, useE2eeAttachmentRenderer } from '../../hooks/useE2eeAttachmentRenderer';\n\nlet activeChannelInfoPreviewLoads = 0;\nconst queuedChannelInfoPreviewLoads: Array<() => void> = [];\n\nfunction scheduleChannelInfoPreviewLoad(load: () => Promise<unknown>): void {\n const run = () => {\n activeChannelInfoPreviewLoads += 1;\n void load().finally(() => {\n activeChannelInfoPreviewLoads = Math.max(0, activeChannelInfoPreviewLoads - 1);\n const next = queuedChannelInfoPreviewLoads.shift();\n if (next) next();\n });\n };\n if (activeChannelInfoPreviewLoads < E2EE_PREVIEW_MAX_CONCURRENT) run();\n else queuedChannelInfoPreviewLoads.push(run);\n}\n\nconst E2eeMediaGridItem: React.FC<{\n item: AttachmentItem;\n}> = ({ item }) => {\n const { activeChannel } = useChatClient();\n const previewRef = useRef<HTMLDivElement | null>(null);\n const manifest = item.e2ee_manifest;\n const preview = useE2eeAttachmentRenderer(activeChannel, manifest, 'preview');\n const original = useE2eeAttachmentRenderer(activeChannel, manifest, 'original');\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const hasPreview = Boolean(manifest?.assets.some((asset) => asset.kind === 'preview'));\n const isVideo = item.attachment_type === 'video';\n const isImage = item.attachment_type === 'image';\n\n useEffect(() => {\n if (!manifest || !hasPreview || preview.url || preview.loading || preview.error) return;\n const element = previewRef.current;\n if (!element || typeof IntersectionObserver === 'undefined') {\n scheduleChannelInfoPreviewLoad(preview.load);\n return;\n }\n let scheduled = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (scheduled) return;\n if (entries.some((entry) => entry.isIntersecting)) {\n scheduled = true;\n observer.disconnect();\n scheduleChannelInfoPreviewLoad(preview.load);\n }\n },\n { rootMargin: '120px' },\n );\n observer.observe(element);\n return () => observer.disconnect();\n }, [hasPreview, manifest, preview.error, preview.load, preview.loading, preview.url]);\n\n const progressLabel = original.progress?.percentage\n ? `${original.progress.phase} ${original.progress.percentage}%`\n : original.loading\n ? original.progress?.phase || 'Loading'\n : undefined;\n\n const openOriginal = useCallback(async () => {\n if (!manifest) return;\n if (isImage || isVideo) {\n setLightboxOpen(true);\n if (isVideo && !original.streamUrl && !original.streamLoading) {\n void original.loadStream().then((streamUrl) => {\n if (!streamUrl && !original.url && !original.loading) void original.load();\n });\n } else if (!original.url && !original.loading && !original.streamUrl) void original.load();\n return;\n }\n await original.download(item.file_name);\n }, [isImage, isVideo, item.file_name, manifest, original]);\n\n const lightboxItems = useMemo<MediaLightboxItem[]>(\n () => [\n {\n type: isVideo ? 'video' : 'image',\n src: original.streamUrl || original.url,\n posterSrc: preview.url,\n alt: item.file_name,\n loading: original.loading || (lightboxOpen && !original.streamUrl && !original.url && !original.error),\n progressLabel,\n download: async () => {\n await original.download(item.file_name);\n },\n onPlaybackError: async () => {\n await original.disposeStream();\n if (!original.url && !original.loading) await original.load();\n },\n onDispose: original.disposeStream,\n },\n ],\n [isVideo, item.file_name, lightboxOpen, original, preview.url, progressLabel],\n );\n\n return (\n <div className=\"ermis-channel-info__media-item\" onClick={openOriginal} ref={previewRef} title={item.file_name}>\n {!preview.url && <div className=\"ermis-channel-info__media-shimmer\" />}\n {preview.url ? (\n <div className={isVideo ? 'ermis-channel-info__media-video-thumb' : undefined}>\n <img src={preview.url} alt={item.file_name || 'encrypted media'} loading=\"lazy\" decoding=\"async\" />\n {(isVideo || original.loading) && (\n <div className=\"ermis-channel-info__media-play-icon\">\n {original.loading ? (\n <span className=\"ermis-channel-info__media-spinner\" />\n ) : (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n )}\n </div>\n )}\n </div>\n ) : (\n <div className=\"ermis-channel-info__media-video-thumb\">\n <div className=\"ermis-channel-info__media-play-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n )}\n {lightboxOpen && (\n <MediaLightbox items={lightboxItems} isOpen={lightboxOpen} onClose={() => setLightboxOpen(false)} />\n )}\n </div>\n );\n};\n\nexport const MediaGridItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(\n ({ item, onClick }) => {\n if (item.e2ee_manifest || item.e2ee_manifest_missing) return <E2eeMediaGridItem item={item} />;\n const src = item.thumb_url || item.url;\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => {\n preloadImage(src);\n }, [src]);\n\n // Fallback checks for browser cache when JS preload didn't catch it\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const isVideo = item.attachment_type === 'video';\n\n return (\n <div className=\"ermis-channel-info__media-item\" onClick={() => onClick(item.url)} title={item.file_name}>\n {/* Shimmer placeholder while loading */}\n {!loaded && <div className=\"ermis-channel-info__media-shimmer\" />}\n\n {isVideo ? (\n <div className=\"ermis-channel-info__media-video-thumb\">\n {item.thumb_url ? (\n <img\n ref={imgRef}\n src={item.thumb_url}\n alt={item.file_name || 'video'}\n loading=\"lazy\"\n decoding=\"async\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n ) : (\n <video\n src={item.url}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n <div className=\"ermis-channel-info__media-play-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n ) : (\n <img\n ref={imgRef}\n src={src}\n alt={item.file_name || 'media'}\n loading=\"lazy\"\n decoding=\"async\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n </div>\n );\n },\n (prev, next) => prev.item.id === next.item.id,\n);\n(MediaGridItem as any).displayName = 'MediaGridItem';\n\nexport const MediaRow = React.memo(\n ({\n row,\n onClick,\n MediaItemComponent = MediaGridItem,\n }: {\n row: AttachmentItem[];\n onClick: (url: string) => void;\n MediaItemComponent?: React.ComponentType<{ item: AttachmentItem; onClick: (url: string) => void }>;\n }) => {\n return (\n <div className=\"ermis-channel-info__media-grid-row\">\n {row.map((item) => (\n <MediaItemComponent key={item.id} item={item} onClick={onClick} />\n ))}\n {row.length < 3 &&\n Array.from({ length: 3 - row.length }).map((_, i) => (\n <div key={`empty-${i}`} className=\"ermis-channel-info__media-item ermis-channel-info__media-item--empty\" />\n ))}\n </div>\n );\n },\n (prev, next) => {\n if (prev.row.length !== next.row.length) return false;\n return prev.row.every((item, i) => item.id === next.row[i].id);\n },\n);\n(MediaRow as any).displayName = 'MediaRow';\n","import React, { useState, useMemo } from 'react';\nimport { formatRelativeDate, extractDomain, isImagePreloaded, preloadImage } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const LinkListItem: React.FC<{ item: AttachmentItem }> = React.memo(({ item }) => {\n const displayUrl = item.og_scrape_url || item.title_link || item.url;\n const domain = extractDomain(displayUrl);\n\n // Preload link preview image if available\n const imgSrc = item.image_url;\n const alreadyCached = imgSrc ? isImagePreloaded(imgSrc) : true;\n const [imgLoaded, setImgLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => { if (imgSrc) preloadImage(imgSrc); }, [imgSrc]);\n\n React.useEffect(() => {\n if (!imgLoaded && imgRef.current?.complete) {\n setImgLoaded(true);\n }\n }, [imgLoaded, imgSrc]);\n\n return (\n <a\n className=\"ermis-channel-info__link-item\"\n href={displayUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <div className=\"ermis-channel-info__link-icon\">\n {imgSrc ? (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {!imgLoaded && <div className=\"ermis-channel-info__media-shimmer\" style={{ borderRadius: '8px' }} />}\n <img\n ref={imgRef}\n src={imgSrc}\n alt=\"\"\n className=\"ermis-channel-info__link-preview-img\"\n loading=\"lazy\"\n onLoad={() => setImgLoaded(true)}\n style={{ opacity: imgLoaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n </div>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-channel-info__link-content\">\n <span className=\"ermis-channel-info__link-title\">\n {item.title || item.file_name || domain}\n </span>\n <span className=\"ermis-channel-info__link-domain\">{domain}</span>\n </div>\n <span className=\"ermis-channel-info__link-date\">{formatRelativeDate(item.created_at)}</span>\n </a>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(LinkListItem as any).displayName = 'LinkListItem';\n","import React from 'react';\nimport { formatFileSize, formatRelativeDate, getDisplayName } from '../../utils';\nimport { getFileIcon } from './utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const FileListItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const displayName = getDisplayName(item.file_name);\n const ext = item.file_name.split('.').pop()?.toUpperCase() || 'FILE';\n\n return (\n <div\n className=\"ermis-channel-info__file-item\"\n onClick={() => onClick(item.url)}\n >\n <div className=\"ermis-channel-info__file-icon\">\n {getFileIcon(item.content_type, item.file_name)}\n <span className=\"ermis-channel-info__file-ext\">{ext}</span>\n </div>\n <div className=\"ermis-channel-info__file-info\">\n <span className=\"ermis-channel-info__file-name\" title={item.file_name}>\n {displayName}\n </span>\n <div className=\"ermis-channel-info__file-meta\">\n <span>{formatFileSize(item.content_length)}</span>\n <span className=\"ermis-channel-info__file-meta-dot\">·</span>\n <span>{formatRelativeDate(item.created_at)}</span>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__file-download\"\n onClick={(e) => {\n e.stopPropagation();\n onClick(item.url);\n }}\n aria-label=\"Download\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(FileListItem as any).displayName = 'FileListItem';\n","import React, { useState } from 'react';\nimport { Dropdown } from '../Dropdown';\nimport type { ChannelInfoMemberItemProps } from '../../types';\nimport { CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const MemberListItem = React.memo(({\n member, AvatarComponent, \n onRemove, canRemove, \n onBan, canBan, \n onUnban, canUnban, \n onPromote, canPromote, \n onDemote, canDemote \n}: ChannelInfoMemberItemProps) => {\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const isOpen = anchorRect !== null;\n\n if (!member) return null;\n const role = member.channel_role || CHANNEL_ROLES.MEMBER;\n const hasActions = canRemove || canBan || canUnban || canPromote || canDemote;\n\n return (\n <div className=\"ermis-channel-info__member-item\">\n <AvatarComponent image={member.user?.avatar} name={member.user?.name || member.user?.id} size={36} />\n <div className=\"ermis-channel-info__member-info\">\n <span className=\"ermis-channel-info__member-name\">{member.user?.name || member.user?.id}</span>\n <span className={`ermis-channel-info__member-role ermis-channel-info__member-role--${role.toLowerCase()}`}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </span>\n </div>\n \n {hasActions && (\n <>\n <button\n className=\"ermis-channel-info__member-actions-btn\"\n onClick={(e) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n }}\n aria-label=\"Member actions\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n \n <Dropdown\n isOpen={isOpen}\n anchorRect={anchorRect}\n onClose={() => setAnchorRect(null)}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {canPromote && onPromote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onPromote(member.user?.id || member.user_id); setAnchorRect(null); }}>Promote to Moder</button>\n )}\n {canDemote && onDemote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onDemote(member.user?.id || member.user_id); setAnchorRect(null); }}>Demote to Member</button>\n )}\n {canBan && onBan && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onBan(member.user?.id || member.user_id); setAnchorRect(null); }}>Ban Member</button>\n )}\n {canUnban && onUnban && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onUnban(member.user?.id || member.user_id); setAnchorRect(null); }}>Unban Member</button>\n )}\n {canRemove && onRemove && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onRemove(member.user?.id || member.user_id); setAnchorRect(null); }}>Remove from Channel</button>\n )}\n </div>\n </Dropdown>\n </>\n )}\n </div>\n );\n}, (prev, next) => {\n return prev.member === next.member &&\n prev.AvatarComponent === next.AvatarComponent &&\n prev.canRemove === next.canRemove &&\n prev.canBan === next.canBan &&\n prev.canUnban === next.canUnban &&\n prev.canPromote === next.canPromote &&\n prev.canDemote === next.canDemote;\n});\n(MemberListItem as any).displayName = 'MemberListItem';\n","import React from 'react';\n\nexport const TabEmptyState: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-channel-info__media-empty\">\n <div className=\"ermis-channel-info__media-empty-icon\">\n {label === 'media' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )}\n {label === 'links' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </svg>\n )}\n {label === 'files' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n )}\n </div>\n <span>No {label} shared yet</span>\n </div>\n));\n(TabEmptyState as any).displayName = 'TabEmptyState';\n\nexport const TabLoadingState: React.FC<{ tab?: string }> = React.memo(() => (\n <div className=\"ermis-channel-info__media-loading\">\n <div className=\"ermis-channel-info__media-spinner\" />\n </div>\n));\n(TabLoadingState as any).displayName = 'TabLoadingState';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal as DefaultModal } from '../Modal';\nimport { UserPicker } from '../UserPicker';\nimport { Avatar } from '../Avatar';\nimport { useChatComponents } from '../../context/ChatComponentsContext';\nimport type { AddMemberModalProps, UserPickerUser } from '../../types';\n\nexport const AddMemberModal: React.FC<AddMemberModalProps> = ({\n channel,\n currentMembers,\n onClose,\n AvatarComponent = Avatar,\n title = 'Add Member',\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n addLabel = 'Add',\n addingLabel = 'Adding...',\n addedLabel = 'Added',\n UserItemComponent,\n SearchInputComponent,\n}) => {\n const { ModalComponent } = useChatComponents();\n const Modal = ModalComponent || DefaultModal;\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n const [isAdding, setIsAdding] = useState(false);\n\n // Exclude existing members from the picker\n const excludeUserIds = useMemo(\n () => currentMembers.map((m: any) => m.user_id),\n [currentMembers],\n );\n\n\n const handleSelectionChange = useCallback((users: UserPickerUser[]) => {\n setSelectedUsers(users);\n }, []);\n\n const handleAdd = useCallback(async () => {\n if (selectedUsers.length === 0 || isAdding) return;\n try {\n setIsAdding(true);\n const memberIds = selectedUsers.map(u => u.id);\n const encryptionManager = channel.getClient().encryptionManager;\n if (channel.data?.mls_enabled && encryptionManager?.initialized && channel.id && channel.cid) {\n await encryptionManager.addMembers(channel.type, channel.id, channel.cid, memberIds);\n } else {\n await channel.addMembers(memberIds);\n }\n onClose();\n } catch (err) {\n console.error('Failed to add members:', err);\n } finally {\n setIsAdding(false);\n }\n }, [selectedUsers, isAdding, channel, onClose]);\n\n const footer = (\n <button\n className=\"ermis-modal-add-btn\"\n onClick={handleAdd}\n disabled={selectedUsers.length === 0 || isAdding}\n >\n {isAdding\n ? addingLabel\n : `${addLabel} ${selectedUsers.length > 0 ? `(${selectedUsers.length})` : ''}`}\n </button>\n );\n\n return (\n <Modal isOpen onClose={onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <UserPicker\n mode=\"checkbox\"\n friendsOnly={true}\n onSelectionChange={handleSelectionChange}\n excludeUserIds={excludeUserIds}\n pageSize={30}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n SearchInputComponent={SearchInputComponent}\n searchPlaceholder={searchPlaceholder}\n loadingText={loadingText}\n emptyText={emptyText}\n selectedEmptyLabel=\"Select users to add...\"\n />\n </Modal>\n );\n};\n","import React, { useState, useEffect, useMemo, useCallback, useRef, useTransition } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { VList as _VList, type VListHandle } from 'virtua';\nconst VList = _VList as any;\nimport type {\n UserPickerProps,\n UserPickerItemProps,\n UserPickerSelectedBoxProps,\n UserPickerUser,\n} from '../types';\nimport { isFriendChannel } from '../channelRoleUtils';\nimport { removeAccents } from '../utils';\n\n/* ---------- Constants ---------- */\nconst DEFAULT_PAGE_SIZE = 30;\nconst SEARCH_DEBOUNCE_MS = 500;\n\n/* ---------- Static styles ---------- */\nconst LIST_STYLE: React.CSSProperties = { height: '100%' };\n\n/* ==========================================================\n Default Sub-Components\n ========================================================== */\n\n/** Check icon for selected state */\nconst CheckIcon: React.FC = () => (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n);\n\n/** Default user row */\nconst DefaultUserItem: React.FC<UserPickerItemProps> = React.memo(({\n user, selected, disabled, mode, onToggle, AvatarComponent,\n}) => {\n const handleClick = useCallback(() => {\n if (!disabled) onToggle(user);\n }, [disabled, onToggle, user]);\n\n const inputClass = [\n 'ermis-user-picker__input',\n mode === 'radio' ? 'ermis-user-picker__input--radio' : 'ermis-user-picker__input--checkbox',\n selected ? 'ermis-user-picker__input--checked' : '',\n ].join(' ');\n\n const itemClass = [\n 'ermis-user-picker__item',\n selected ? 'ermis-user-picker__item--selected' : '',\n disabled ? 'ermis-user-picker__item--disabled' : '',\n ].join(' ');\n\n const detail = user.email || user.phone || '';\n\n return (\n <div className={itemClass} onClick={handleClick} role=\"option\" aria-selected={selected}>\n <div className={inputClass}>\n {selected && <CheckIcon />}\n </div>\n <AvatarComponent image={user.avatar} name={user.name || user.id} size={36} />\n <div className=\"ermis-user-picker__info\">\n <span className=\"ermis-user-picker__name\">{user.name || user.id}</span>\n {detail && <span className=\"ermis-user-picker__detail\">{detail}</span>}\n </div>\n </div>\n );\n});\nDefaultUserItem.displayName = 'DefaultUserItem';\n\n/** Default search input */\nconst DefaultSearchInput: React.FC<{ value: string; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; placeholder: string }> = ({ value, onChange, placeholder }) => (\n <div className=\"ermis-user-picker__search\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={onChange}\n autoFocus\n />\n </div>\n);\n\n/** Default selected users chip box */\nconst DefaultSelectedBox: React.FC<UserPickerSelectedBoxProps> = React.memo(({\n users, onRemove, AvatarComponent, emptyLabel,\n}) => (\n <div className=\"ermis-user-picker__selected-box\">\n {users.length === 0 && emptyLabel && (\n <span className=\"ermis-user-picker__selected-empty\">{emptyLabel}</span>\n )}\n {users.map(u => (\n <div key={u.id} className=\"ermis-user-picker__chip\">\n <AvatarComponent image={u.avatar} name={u.name || u.id} size={20} />\n <span className=\"ermis-user-picker__chip-name\">{u.name || u.id}</span>\n <button\n className=\"ermis-user-picker__chip-remove\"\n onClick={() => onRemove(u.id)}\n aria-label={`Remove ${u.name || u.id}`}\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n));\nDefaultSelectedBox.displayName = 'DefaultSelectedBox';\n\n/* ==========================================================\n UserPicker Component\n ========================================================== */\n\n// Global cache to persist users across UserPicker unmounts/remounts (e.g. during tab switch)\nconst globalUsersCache: Record<string, { users: UserPickerUser[], page: number, hasMore: boolean }> = {};\n\nexport const UserPicker: React.FC<UserPickerProps> = ({\n mode,\n onSelectionChange,\n excludeUserIds,\n initialSelectedUsers,\n pageSize = DEFAULT_PAGE_SIZE,\n AvatarComponent = Avatar,\n UserItemComponent,\n SelectedBoxComponent,\n SearchInputComponent,\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n loadingMoreText = 'Loading more...',\n selectedEmptyLabel,\n friendsOnly,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [allUsers, setAllUsers] = useState<UserPickerUser[]>([]);\n const [page, setPage] = useState(1);\n const [hasMore, setHasMore] = useState(true);\n const [loading, setLoading] = useState(true);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const [remoteUsers, setRemoteUsers] = useState<UserPickerUser[]>([]);\n const [isSearching, setIsSearching] = useState(false);\n\n const [searchInput, setSearchInput] = useState('');\n const [search, setSearch] = useState('');\n const [isPendingFilter, startTransition] = useTransition();\n\n const [selectedMap, setSelectedMap] = useState<Map<string, UserPickerUser>>(() => {\n const map = new Map<string, UserPickerUser>();\n initialSelectedUsers?.forEach(u => map.set(u.id, u));\n return map;\n });\n\n const vlistRef = useRef<VListHandle>(null);\n\n /* ---------- Resolved sub-components ---------- */\n const UserRow = UserItemComponent || DefaultUserItem;\n const SearchInput = SearchInputComponent || DefaultSearchInput;\n const SelectedBox = SelectedBoxComponent || DefaultSelectedBox;\n\n /* ---------- Excluded IDs set ---------- */\n const excludeSet = useMemo(() => new Set(excludeUserIds || []), [excludeUserIds]);\n\n /* ---------- Search handler ---------- */\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearchInput(val);\n startTransition(() => {\n setSearch(val);\n });\n }, [startTransition]);\n\n /* ---------- 1. Fetch initial page ---------- */\n useEffect(() => {\n let active = true;\n const fetchUsers = async () => {\n if (!client) return;\n\n // For friendsOnly mode, always read fresh data from activeChannels.\n // Do NOT use globalUsersCache here — the friend list can change at any\n // time (e.g. a new friend request was accepted) and caching would\n // return stale results, hiding the newly added friend.\n if (friendsOnly) {\n const friends: UserPickerUser[] = [];\n const seenIds = new Set<string>();\n \n for (const channel of Object.values(client.activeChannels)) {\n const members = channel.state?.members;\n if (!members) continue;\n\n for (const [memberId, member] of Object.entries(members)) {\n if (memberId === client.userID) continue;\n \n if (isFriendChannel(channel, memberId, client.userID as string) && !seenIds.has(memberId)) {\n if (member.user) {\n friends.push(member.user as UserPickerUser);\n seenIds.add(memberId);\n }\n }\n }\n }\n \n if (active) {\n setAllUsers(friends);\n setHasMore(false);\n setPage(1);\n setLoading(false);\n }\n return;\n }\n\n const cacheKey = `${client.userID || 'anon'}-${pageSize}`;\n\n if (globalUsersCache[cacheKey] && globalUsersCache[cacheKey].users.length > 0) {\n const cached = globalUsersCache[cacheKey];\n setAllUsers(cached.users);\n setHasMore(cached.hasMore);\n setPage(cached.page);\n setLoading(false);\n return;\n }\n\n try {\n setLoading(true);\n const response = await client.queryUsers(pageSize, 1);\n if (active && response.data) {\n setAllUsers(response.data);\n setHasMore(response.data.length >= pageSize);\n setPage(1);\n\n globalUsersCache[cacheKey] = {\n users: response.data,\n page: 1,\n hasMore: response.data.length >= pageSize\n };\n }\n } catch (err) {\n console.error('[UserPicker] Error fetching users:', err);\n } finally {\n if (active) setLoading(false);\n }\n };\n fetchUsers();\n return () => { active = false; };\n }, [client, pageSize, friendsOnly]);\n\n /* ---------- 2. Load more (infinite scroll) ---------- */\n const loadMore = useCallback(async () => {\n if (!client || loadingMore || !hasMore || search.trim()) return;\n const nextPage = page + 1;\n setLoadingMore(true);\n try {\n const response = await client.queryUsers(pageSize, nextPage);\n if (response.data) {\n setAllUsers(prev => {\n const existingIds = new Set(prev.map(u => u.id));\n const newUsers = response.data.filter((u: UserPickerUser) => !existingIds.has(u.id));\n const combined = [...prev, ...newUsers];\n\n if (client) {\n const cacheKey = `${client.userID || 'anon'}-${pageSize}`;\n globalUsersCache[cacheKey] = {\n users: combined,\n page: nextPage,\n hasMore: response.data.length >= pageSize\n };\n }\n\n return combined;\n });\n setHasMore(response.data.length >= pageSize);\n setPage(nextPage);\n }\n } catch (err) {\n console.error('[UserPicker] Error loading more users:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [client, loadingMore, hasMore, page, pageSize, search]);\n\n /* ---------- 3. Local filter ---------- */\n const localFilteredUsers = useMemo(() => {\n const term = removeAccents(search.toLowerCase().trim());\n if (!term) return allUsers;\n const result: UserPickerUser[] = [];\n for (const u of allUsers) {\n const name = removeAccents((u.name || '').toLowerCase());\n const email = removeAccents((u.email || '').toLowerCase());\n const phone = removeAccents((u.phone || '').toLowerCase());\n if (name.startsWith(term) || email.startsWith(term) || phone.startsWith(term)) {\n result.push(u);\n if (result.length >= 100) break; // optimize for large room\n }\n }\n return result;\n }, [search, allUsers]);\n\n /* ---------- 4. Remote search fallback ---------- */\n useEffect(() => {\n if (!search.trim() || localFilteredUsers.length > 0 || friendsOnly) {\n setRemoteUsers([]);\n setIsSearching(false);\n return;\n }\n\n let cancelled = false;\n const timer = setTimeout(async () => {\n setIsSearching(true);\n try {\n const response = await client.searchUsers(1, 25, search.trim());\n if (!cancelled && response.data) {\n setRemoteUsers(response.data);\n }\n } catch (err) {\n console.error('[UserPicker] Error searching remote users:', err);\n } finally {\n if (!cancelled) setIsSearching(false);\n }\n }, SEARCH_DEBOUNCE_MS);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [search, localFilteredUsers.length, client]);\n\n /* ---------- 5. Derived display list ---------- */\n const usersToDisplay = useMemo(() => {\n const list = (search.trim() && localFilteredUsers.length === 0)\n ? remoteUsers\n : localFilteredUsers;\n return list.filter(u => !excludeSet.has(u.id));\n }, [search, localFilteredUsers, remoteUsers, excludeSet]);\n\n const isListLoading = loading || isSearching || isPendingFilter;\n\n /* ---------- 6. Selection handlers ---------- */\n const handleToggle = useCallback((user: UserPickerUser) => {\n // Don't allow toggling disabled users (current user or excluded)\n if (user.id === currentUserId || excludeSet.has(user.id)) return;\n\n setSelectedMap(prev => {\n const next = new Map(prev);\n if (mode === 'radio') {\n // Radio: clear all, set this one (or deselect if same)\n if (next.has(user.id)) {\n next.clear();\n } else {\n next.clear();\n next.set(user.id, user);\n }\n } else {\n // Checkbox: toggle\n if (next.has(user.id)) {\n next.delete(user.id);\n } else {\n next.set(user.id, user);\n }\n }\n return next;\n });\n }, [mode, currentUserId, excludeSet]);\n\n // Notify parent of selection changes\n useEffect(() => {\n onSelectionChange?.(Array.from(selectedMap.values()));\n }, [selectedMap, onSelectionChange]);\n\n const handleRemoveSelected = useCallback((userId: string) => {\n setSelectedMap(prev => {\n const next = new Map(prev);\n next.delete(userId);\n return next;\n });\n }, []);\n\n /* ---------- 7. Scroll handler for infinite scroll ---------- */\n const handleScroll = useCallback((offset: number) => {\n // VList provides scroll offset. We detect near-bottom using the ref\n const el = vlistRef.current;\n if (!el) return;\n // scrollSize = total scroll height, viewportSize = visible height\n const scrollSize = (el as any).scrollSize ?? 0;\n const viewportSize = (el as any).viewportSize ?? 0;\n if (scrollSize > 0 && offset + viewportSize >= scrollSize - 50) {\n loadMore();\n }\n }, [loadMore]);\n\n /* ---------- Render ---------- */\n const selectedArr = useMemo(() => Array.from(selectedMap.values()), [selectedMap]);\n\n return (\n <div className=\"ermis-user-picker\" role=\"listbox\" aria-multiselectable={mode === 'checkbox'}>\n {/* Selected Users Box (checkbox mode only) */}\n {mode === 'checkbox' && (\n <SelectedBox\n users={selectedArr}\n onRemove={handleRemoveSelected}\n AvatarComponent={AvatarComponent}\n emptyLabel={selectedEmptyLabel}\n />\n )}\n\n {/* Search Input */}\n <SearchInput\n value={searchInput}\n onChange={handleSearchChange}\n placeholder={searchPlaceholder}\n />\n\n {/* User List */}\n <div className=\"ermis-user-picker__list\">\n {isListLoading ? (\n <div className=\"ermis-user-picker__loading\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingText}\n </div>\n ) : usersToDisplay.length === 0 ? (\n <div className=\"ermis-user-picker__empty\">{emptyText}</div>\n ) : (\n <VList ref={vlistRef} style={LIST_STYLE} onScroll={handleScroll}>\n {usersToDisplay.map(user => (\n <UserRow\n key={user.id}\n user={user}\n selected={selectedMap.has(user.id)}\n disabled={user.id === currentUserId || excludeSet.has(user.id)}\n mode={mode}\n onToggle={handleToggle}\n AvatarComponent={AvatarComponent}\n />\n ))}\n {loadingMore && (\n <div className=\"ermis-user-picker__load-more\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingMoreText}\n </div>\n )}\n </VList>\n )}\n </div>\n </div>\n );\n};\n\nUserPicker.displayName = 'UserPicker';\n","import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { Modal as DefaultModal } from '../Modal';\nimport { useChatComponents } from '../../context/ChatComponentsContext';\nimport type { EditChannelModalProps, EditChannelData } from '../../types';\nimport { isGroupChannel } from '../../channelTypeUtils';\n\nconst DEFAULT_MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB\n\nexport const EditChannelModal: React.FC<EditChannelModalProps> = React.memo(({\n channel,\n onClose,\n onSave,\n AvatarComponent,\n title = 'Edit Channel',\n nameLabel = 'Channel Name',\n descriptionLabel = 'Description',\n namePlaceholder = 'Enter channel name',\n descriptionPlaceholder = 'Enter channel description',\n publicLabel = 'Public Channel',\n saveLabel = 'Save',\n cancelLabel = 'Cancel',\n savingLabel = 'Saving...',\n changeAvatarLabel = 'Change Avatar',\n imageAccept = 'image/*',\n maxImageSize = DEFAULT_MAX_IMAGE_SIZE,\n maxImageSizeError = 'Image must be less than 5MB',\n}) => {\n // Original values from channel data\n const originalName = (channel.data?.name as string) || '';\n const originalImage = (channel.data?.image as string) || '';\n const originalDescription = (channel.data?.description as string) || '';\n const originalPublic = Boolean(channel.data?.public);\n const isTeamOrMeetingChannel = isGroupChannel(channel);\n const { ModalComponent } = useChatComponents();\n const Modal = ModalComponent || DefaultModal;\n\n // Form state\n const [name, setName] = useState(originalName);\n const [description, setDescription] = useState(originalDescription);\n const [isPublic, setIsPublic] = useState(originalPublic);\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n const [selectedFile, setSelectedFile] = useState<File | null>(null);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Clean up object URL on unmount or when preview changes\n useEffect(() => {\n return () => {\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n };\n }, [previewUrl]);\n\n const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n // Validate it's an image\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n\n // Validate size\n if (file.size > maxImageSize) {\n setError(maxImageSizeError);\n return;\n }\n\n setError(null);\n // Revoke previous preview\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n const url = URL.createObjectURL(file);\n setPreviewUrl(url);\n setSelectedFile(file);\n\n // Reset input so same file can be re-selected\n e.target.value = '';\n }, [maxImageSize, maxImageSizeError, previewUrl]);\n\n const handleAvatarClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Check if anything changed — only send changed fields\n const buildPayload = useCallback((): EditChannelData | null => {\n const payload: EditChannelData = {};\n let hasChanges = false;\n\n if (name.trim() !== originalName) {\n payload.name = name.trim();\n hasChanges = true;\n }\n if (description.trim() !== originalDescription) {\n payload.description = description.trim();\n hasChanges = true;\n }\n if (isTeamOrMeetingChannel && isPublic !== originalPublic) {\n payload.public = isPublic;\n hasChanges = true;\n }\n // Image is handled separately (upload first), but mark as changed\n if (selectedFile) {\n hasChanges = true;\n }\n\n return hasChanges ? payload : null;\n }, [name, description, isPublic, selectedFile, originalName, originalDescription, originalPublic, isTeamOrMeetingChannel]);\n\n const handleSave = useCallback(async () => {\n const payload = buildPayload();\n if (!payload && !selectedFile) {\n onClose();\n return;\n }\n\n setIsSaving(true);\n setError(null);\n\n try {\n // If consumer provides custom save handler, delegate entirely\n if (onSave) {\n if (selectedFile) {\n const response = await channel.uploadFilePresigned(selectedFile, selectedFile.name, selectedFile.type);\n (payload || {} as EditChannelData).image = response.file;\n }\n await onSave(payload || {});\n onClose();\n return;\n }\n\n // Default save logic\n const finalPayload: EditChannelData = payload || {};\n\n // Upload image if changed\n if (selectedFile) {\n const response = await channel.uploadFilePresigned(selectedFile, selectedFile.name, selectedFile.type);\n finalPayload.image = response.file;\n }\n\n // Only call update if there's something to update\n if (Object.keys(finalPayload).length > 0) {\n await channel.update(finalPayload as any);\n }\n\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update channel');\n } finally {\n setIsSaving(false);\n }\n }, [buildPayload, selectedFile, onSave, channel, onClose]);\n\n // Determine displayed avatar image\n const displayImage = previewUrl || originalImage || undefined;\n\n const footerContent = (\n <div className=\"ermis-channel-info__edit-footer-buttons\">\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--cancel\"\n onClick={onClose}\n disabled={isSaving}\n >\n {cancelLabel}\n </button>\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--save\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? savingLabel : saveLabel}\n </button>\n </div>\n );\n\n return (\n <Modal\n isOpen={true}\n onClose={isSaving ? () => {} : onClose}\n title={title}\n footer={footerContent}\n maxWidth=\"420px\"\n >\n <div className=\"ermis-channel-info__edit-body\">\n {/* Avatar section */}\n <div className=\"ermis-channel-info__edit-avatar-section\">\n <div className=\"ermis-channel-info__edit-avatar-wrap\" onClick={handleAvatarClick}>\n <AvatarComponent image={displayImage} name={name || originalName} size={80} />\n <div className=\"ermis-channel-info__edit-avatar-overlay\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\" />\n <circle cx=\"12\" cy=\"13\" r=\"4\" />\n </svg>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__edit-avatar-btn\"\n onClick={handleAvatarClick}\n type=\"button\"\n disabled={isSaving}\n >\n {changeAvatarLabel}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={imageAccept}\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n />\n </div>\n\n {/* Name field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{nameLabel}</label>\n <input\n className=\"ermis-channel-info__edit-input\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n />\n </div>\n\n {/* Description field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-channel-info__edit-textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n />\n </div>\n\n {/* Public toggle — only for team channels */}\n {isTeamOrMeetingChannel && (\n <div className=\"ermis-channel-info__edit-field ermis-channel-info__edit-field--toggle\">\n <label className=\"ermis-channel-info__edit-label\">{publicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-channel-info__edit-toggle ${isPublic ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isSaving}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"ermis-channel-info__edit-error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nEditChannelModal.displayName = 'EditChannelModal';\n","import React, { useRef, useCallback, useMemo, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { replaceMentionsForPreview, formatRelativeDate } from '../../utils';\nimport { Avatar } from '../Avatar';\nimport { Panel as DefaultPanel } from '../Panel';\nimport { useChatComponents } from '../../context/ChatComponentsContext';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport type { MessageSearchPanelProps } from '../../types';\nimport { useMessageSearch } from './useMessageSearch';\nimport { removeAccents } from '../../utils';\n\n/* ----------------------------------------------------------\n Highlight utility (Accent-insensitive)\n ---------------------------------------------------------- */\n\nexport const HighlightedText: React.FC<{ text: string; term: string }> = React.memo(({ text, term }) => {\n if (!term.trim()) return <>{text}</>;\n\n const cleanTerm = removeAccents(term).toLowerCase();\n if (!cleanTerm) return <>{text}</>;\n\n const parts = [];\n let currentIndex = 0;\n const cleanText = removeAccents(text).toLowerCase();\n\n while (true) {\n const startMatch = cleanText.indexOf(cleanTerm, currentIndex);\n if (startMatch === -1) {\n if (currentIndex < text.length) {\n parts.push(<span key={currentIndex}>{text.slice(currentIndex)}</span>);\n }\n break;\n }\n\n if (startMatch > currentIndex) {\n parts.push(<span key={`text-${currentIndex}`}>{text.slice(currentIndex, startMatch)}</span>);\n }\n\n const endMatch = startMatch + cleanTerm.length;\n parts.push(\n <mark key={`mark-${startMatch}`} className=\"ermis-search-panel__highlight\">\n {text.slice(startMatch, endMatch)}\n </mark>\n );\n\n currentIndex = endMatch;\n }\n\n return <>{parts.length > 0 ? parts : text}</>;\n});\nHighlightedText.displayName = 'HighlightedText';\n\n/* ----------------------------------------------------------\n MessageSearchPanel\n ---------------------------------------------------------- */\nexport const MessageSearchPanel: React.FC<MessageSearchPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n AvatarComponent = Avatar,\n placeholder = 'Search messages...',\n title = 'Search Messages',\n emptyText = 'No messages found.',\n loadingText = 'Searching...',\n debounceMs = 500,\n}) => {\n const { setJumpToMessageId } = useChatClient();\n const { PanelComponent } = useChatComponents();\n const Panel = PanelComponent || DefaultPanel;\n\n const {\n query,\n setQuery,\n results,\n loading,\n hasMore,\n loadingMore,\n handleInputChange,\n handleScroll,\n resetSearch,\n userMaps,\n } = useMessageSearch({ channel, isOpen, debounceMs });\n\n // Auto-focus the input when panel opens\n const inputRef = useRef<HTMLInputElement>(null);\n useEffect(() => {\n if (isOpen) {\n setTimeout(() => inputRef.current?.focus(), 300);\n }\n }, [isOpen]);\n\n // Click a result -> jump to that message\n const handleResultClick = useCallback((messageId: string) => {\n setJumpToMessageId(messageId);\n }, [setJumpToMessageId]);\n\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-search-panel\">\n {/* Search Input now inside body */}\n <div className=\"ermis-search-panel__search-box\">\n <div className=\"ermis-search-panel__input-wrap\">\n <svg className=\"ermis-search-panel__input-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n ref={inputRef}\n className=\"ermis-search-panel__input\"\n type=\"text\"\n value={query}\n onChange={handleInputChange}\n placeholder={placeholder}\n />\n {query && (\n <button\n className=\"ermis-search-panel__input-clear\"\n onClick={() => {\n resetSearch();\n inputRef.current?.focus();\n }}\n aria-label=\"Clear\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n <div\n className=\"ermis-search-panel__results\"\n onScroll={handleScroll}\n >\n {/* Initial state — no query yet */}\n {!query.trim() && !loading && results.length === 0 && (\n <div className=\"ermis-search-panel__idle\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <span>{placeholder}</span>\n </div>\n )}\n\n {/* Loading state */}\n {loading && (\n <div className=\"ermis-search-panel__loading\">\n <div className=\"ermis-search-panel__spinner\" />\n <span>{loadingText}</span>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && query.trim() && results.length === 0 && (\n <div className=\"ermis-search-panel__empty\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Results */}\n {!loading && results.map((msg) => {\n let parsedText = '';\n if (msg.text) {\n // Try standard replacement first\n parsedText = replaceMentionsForPreview(msg.text, msg as any, userMaps.original);\n // Fallback: search API may omit mentioned_users array, so we map @0x IDs efficiently\n if (/@0x[a-fA-F0-9]+/i.test(parsedText)) {\n parsedText = parsedText.replace(/@0x[a-fA-F0-9]+/gi, (match) => {\n const matchedId = match.slice(1).toLowerCase();\n return userMaps.lower[matchedId] ? `@${userMaps.lower[matchedId]}` : match;\n });\n }\n }\n\n return (\n <div\n key={msg.id}\n role=\"button\"\n tabIndex={0}\n className=\"ermis-search-panel__result-item\"\n onClick={() => handleResultClick(msg.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleResultClick(msg.id);\n }\n }}\n >\n <AvatarComponent\n image={msg.user?.avatar || msg.user?.image || msg.user?.avatar_url}\n name={msg.user?.name || msg.user_id}\n size={36}\n />\n <div className=\"ermis-search-panel__result-body\">\n <div className=\"ermis-search-panel__result-meta\">\n <span className=\"ermis-search-panel__result-name\">\n {msg.user?.name || msg.user_id || 'Unknown'}\n </span>\n <span className=\"ermis-search-panel__result-time\">\n {msg.created_at ? formatRelativeDate(msg.created_at) : ''}\n </span>\n </div>\n <p className=\"ermis-search-panel__result-text\">\n {parsedText ? (\n <HighlightedText text={parsedText} term={query} />\n ) : (\n <em>Attachment</em>\n )}\n </p>\n </div>\n </div>\n );\n })}\n\n {/* End of results indicator */}\n {!loading && !loadingMore && !hasMore && results.length > 0 && query.trim() && (\n <div className=\"ermis-search-panel__end-indicator\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Loading more indicator */}\n {loadingMore && (\n <div className=\"ermis-search-panel__loading-more\">\n <div className=\"ermis-search-panel__spinner ermis-search-panel__spinner--small\" />\n </div>\n )}\n </div>\n </Panel>\n );\n});\nMessageSearchPanel.displayName = 'MessageSearchPanel';\n","import React, { useEffect, useRef } from 'react';\n\nimport type { PanelProps } from '../types';\n\n/**\n * Reusable sliding panel component.\n * Slides in from the right to overlay itself on whatever container it's placed in.\n * Use it like a Modal but inside a sidebar — call `isOpen` to show/hide.\n */\nexport const Panel: React.FC<PanelProps> = React.memo(({\n isOpen,\n onClose,\n title,\n children,\n headerContent,\n className,\n}) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n // Focus trap: focus the panel when it opens for accessibility\n useEffect(() => {\n if (isOpen && panelRef.current) {\n panelRef.current.focus();\n }\n }, [isOpen]);\n\n return (\n <div\n ref={panelRef}\n className={`ermis-panel${isOpen ? ' ermis-panel--open' : ''}${className ? ` ${className}` : ''}`}\n tabIndex={-1}\n >\n {headerContent ? (\n headerContent\n ) : (\n <div className=\"ermis-panel__header\">\n <button className=\"ermis-panel__back\" onClick={onClose} aria-label=\"Back\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n {title && <h3 className=\"ermis-panel__title\">{title}</h3>}\n </div>\n )}\n <div className=\"ermis-panel__body\">\n {children}\n </div>\n </div>\n );\n});\nPanel.displayName = 'Panel';\n","import { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { buildUserMap } from '../../utils';\nimport type { SearchResultMessage } from '../../types';\n\nexport type UseMessageSearchProps = {\n channel: Channel;\n isOpen: boolean;\n debounceMs?: number;\n};\n\nexport const useMessageSearch = ({ channel, isOpen, debounceMs = 500 }: UseMessageSearchProps) => {\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResultMessage[]>([]);\n const [loading, setLoading] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const offsetRef = useRef(0);\n const queryRef = useRef('');\n\n // Reset all state when the channel changes (or panel closes)\n useEffect(() => {\n setQuery('');\n setResults([]);\n setLoading(false);\n setHasMore(false);\n setLoadingMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n }, [channel?.cid, isOpen]);\n\n // Debounced search\n const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setQuery(value);\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n\n if (!value.trim()) {\n setResults([]);\n setLoading(false);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n return;\n }\n\n setLoading(true);\n\n debounceRef.current = setTimeout(async () => {\n queryRef.current = value;\n offsetRef.current = 0;\n\n try {\n const response = await channel.searchMessage(value, 0);\n // Only apply if this is still the latest query\n if (queryRef.current !== value) return;\n\n if (!response) {\n setResults([]);\n setHasMore(false);\n } else {\n setResults(response.messages || []);\n setHasMore((response.messages?.length || 0) >= 25);\n }\n } catch (err) {\n console.error('Search failed:', err);\n setResults([]);\n setHasMore(false);\n } finally {\n setLoading(false);\n }\n }, debounceMs);\n }, [channel, debounceMs]);\n\n const resetSearch = useCallback(() => {\n setQuery('');\n setResults([]);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n }, []);\n\n // Infinite scroll: load more results\n const handleLoadMore = useCallback(async () => {\n if (loadingMore || !hasMore || !queryRef.current) return;\n\n setLoadingMore(true);\n const nextOffset = offsetRef.current + 25; // offset skips records, limit is 25\n\n try {\n const response = await channel.searchMessage(queryRef.current, nextOffset);\n\n if (!response || !response.messages?.length) {\n setHasMore(false);\n } else {\n offsetRef.current = nextOffset;\n setResults((prev) => [...prev, ...response.messages]);\n setHasMore(response.messages.length >= 25);\n }\n } catch (err) {\n console.error('Load more search results failed:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [channel, hasMore, loadingMore]);\n\n // Scroll handler for infinite scroll container\n const handleScroll = useCallback((e: React.UIEvent<HTMLElement>) => {\n const el = e.currentTarget;\n const threshold = 100;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - threshold) {\n handleLoadMore();\n }\n }, [handleLoadMore]);\n\n // Derived userMap for resolving mentions, with a lowercase variant for fast lookup\n const userMaps = useMemo(() => {\n const original = buildUserMap(channel.state);\n const lower: typeof original = {};\n for (const [id, name] of Object.entries(original)) {\n lower[id.toLowerCase()] = name;\n }\n return { original, lower };\n }, [channel.state]);\n\n return {\n query,\n setQuery,\n results,\n loading,\n hasMore,\n loadingMore,\n handleInputChange,\n handleScroll,\n resetSearch,\n userMaps,\n };\n};\n","import React, { useState, useEffect } from 'react';\nimport { Panel as DefaultPanel } from '../Panel';\nimport { useChatComponents } from '../../context/ChatComponentsContext';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport type { ChannelSettingsPanelProps } from '../../types';\nimport { isGroupChannel } from '../../channelTypeUtils';\nimport { CHANNEL_ROLES } from '../../channelRoleUtils';\n\nimport { useChannelSettings } from './useChannelSettings';\n\nexport const ChannelSettingsPanel: React.FC<ChannelSettingsPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n title = 'Channel Settings',\n slowModeOptions = [\n { label: 'Off', value: 0 },\n { label: '10s', value: 10000 },\n { label: '30s', value: 30000 },\n { label: '1m', value: 60000 },\n { label: '5m', value: 300000 },\n { label: '15m', value: 900000 },\n { label: '1h', value: 3600000 },\n ],\n workspaceTopicsTitle = 'Workspace Topics',\n topicsFeatureName = 'Topics',\n topicsFeatureDescription = 'Allow users to reply to messages with dedicated conversation threads. Disabling this hides the reply-in-topic button for everyone.',\n}) => {\n const { client } = useChatClient();\n const { PanelComponent } = useChatComponents();\n const Panel = PanelComponent || DefaultPanel;\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n\n const {\n slowMode,\n setSlowMode,\n topicsEnabled,\n setTopicsEnabled,\n capabilities,\n toggleCapability,\n keywords,\n newKeyword,\n setNewKeyword,\n handleAddNewKeyword,\n handleRemoveKeyword,\n isSaving,\n error,\n isDirty,\n isOwner,\n handleSave,\n } = useChannelSettings({\n channel: channel as any,\n isOpen,\n onClose,\n currentUserRole,\n });\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleAddNewKeyword();\n }\n };\n\n // We do NOT return null based on !isOpen so the sliding CSS transition is preserved.\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-settings-panel\">\n\n {/* \n This wrapper creates a neat scrollable area with subtle gray background\n which makes white cards pop out smoothly.\n */}\n <div\n className=\"ermis-settings-panel__body\"\n style={{\n flex: 1,\n minHeight: 0,\n padding: '16px',\n overflowY: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '16px',\n background: 'var(--ermis-bg-secondary)'\n }}\n >\n\n {/* Section 1: Permissions */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-primary-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-primary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" />\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Member Permissions\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Slow Mode\n </label>\n <div style={{ position: 'relative' }}>\n <select\n value={slowMode}\n onChange={e => setSlowMode(Number(e.target.value))}\n style={{\n width: '100%',\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n fontWeight: 500,\n appearance: 'none',\n outline: 'none',\n cursor: isSaving ? 'not-allowed' : 'pointer',\n transition: 'border-color 0.2s'\n }}\n disabled={isSaving}\n >\n {slowModeOptions.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n <div style={{ position: 'absolute', right: '14px', top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: 'var(--ermis-text-secondary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Capabilities\n </label>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n {Object.entries(capabilities).map(([key, value], index, arr) => (\n <div\n key={key}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n borderBottom: index < arr.length - 1 ? '1px solid var(--ermis-border-color)' : 'none'\n }}\n >\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {key.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}\n </span>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n className={`ermis-channel-info__edit-toggle ${value ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => toggleCapability(key)}\n disabled={isSaving}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n ))}\n </div>\n </div>\n </section>\n\n {/* Section 2: Content Moderation */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-danger-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-danger)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path>\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Content Moderation\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Keyword Filtering\n </label>\n <div style={{ display: 'flex', gap: '8px', position: 'relative' }}>\n <input\n type=\"text\"\n value={newKeyword}\n onChange={e => setNewKeyword(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type keyword and press Enter or Add...\"\n style={{\n flex: 1,\n minWidth: 0,\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n outline: 'none'\n }}\n disabled={isSaving}\n />\n <button\n type=\"button\"\n onClick={handleAddNewKeyword}\n disabled={isSaving || !newKeyword.trim()}\n style={{\n padding: '0 12px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary-light)',\n color: 'var(--ermis-color-primary)',\n border: 'none',\n fontWeight: 600,\n fontSize: '13px',\n cursor: isSaving || !newKeyword.trim() ? 'not-allowed' : 'pointer',\n opacity: isSaving || !newKeyword.trim() ? 0.6 : 1,\n transition: 'opacity 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center'\n }}\n >\n Add\n </button>\n </div>\n </div>\n\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', minHeight: '32px' }}>\n {keywords.map(kw => (\n <span\n key={kw}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n padding: '3px 8px',\n borderRadius: '16px',\n background: 'var(--ermis-color-danger-light)',\n color: 'var(--ermis-color-danger)',\n border: '1px solid rgba(239, 68, 68, 0.2)',\n fontSize: '12px',\n fontWeight: 600\n }}\n >\n {kw}\n <button\n onClick={() => handleRemoveKeyword(kw)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'transparent',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n color: 'inherit',\n opacity: 0.8,\n }}\n disabled={isSaving}\n aria-label=\"Remove keyword\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </span>\n ))}\n {keywords.length === 0 && (\n <span style={{ fontSize: '14px', color: 'var(--ermis-text-secondary)', padding: '6px 0', fontStyle: 'italic' }}>\n No blacklisted keywords added.\n </span>\n )}\n </div>\n </section>\n\n {/* Section 3: Features */}\n {isGroupChannel(channel) && (\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'rgba(168, 85, 247, 0.1)', padding: '4px', borderRadius: '8px', color: '#a855f7' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"12 2 2 7 12 12 22 7 12 2\"></polygon>\n <polyline points=\"2 17 12 22 22 17\"></polyline>\n <polyline points=\"2 12 12 17 22 12\"></polyline>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n {workspaceTopicsTitle}\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n }}\n >\n <div style={{ display: 'flex', flexDirection: 'column' }}>\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {topicsFeatureName}\n </span>\n <span style={{ fontSize: '12px', color: 'var(--ermis-text-secondary)', marginTop: '2px' }}>\n {topicsFeatureDescription}\n </span>\n {!isOwner && (\n <span style={{ fontSize: '11px', color: 'var(--ermis-color-danger)', marginTop: '4px', fontWeight: 500 }}>\n Only channel owner can change this.\n </span>\n )}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={topicsEnabled}\n className={`ermis-channel-info__edit-toggle ${topicsEnabled ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => isOwner && setTopicsEnabled(!topicsEnabled)}\n disabled={isSaving || !isOwner}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center', cursor: (!isOwner || isSaving) ? 'not-allowed' : 'pointer' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n </div>\n </div>\n </section>\n )}\n\n\n </div>\n\n {/* Footer Area */}\n <div\n className=\"ermis-settings-panel__footer\"\n style={{\n flexShrink: 0,\n padding: '12px 16px',\n background: 'var(--ermis-bg-primary)',\n borderTop: '1px solid var(--ermis-border-color)',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px'\n }}\n >\n {error && (\n <div style={{ color: 'var(--ermis-color-danger)', fontSize: '13px', display: 'flex', alignItems: 'center', gap: '6px', fontWeight: 500 }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" /><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" /></svg>\n {error}\n </div>\n )}\n <button\n onClick={handleSave}\n disabled={isSaving || !isDirty}\n style={{\n width: '100%',\n padding: '10px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary, #006eff)',\n color: '#ffffff',\n border: 'none',\n fontSize: '14px',\n fontWeight: 600,\n cursor: (isSaving || !isDirty) ? 'not-allowed' : 'pointer',\n opacity: (isSaving || !isDirty) ? 0.6 : 1,\n transition: 'all 0.2s ease',\n boxShadow: (isSaving || !isDirty) ? 'none' : '0 4px 12px rgba(0, 110, 255, 0.2)'\n }}\n >\n {isSaving ? (\n <span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}>\n <svg className=\"ermis-spinner\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n </svg>\n Saving...\n </span>\n ) : 'Save Updates'}\n </button>\n </div>\n\n </Panel>\n );\n});\n\nChannelSettingsPanel.displayName = 'ChannelSettingsPanel';\n","import { useState, useEffect, useCallback } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\nexport interface UseChannelSettingsOptions {\n channel: Channel | undefined;\n isOpen?: boolean;\n onClose?: () => void;\n currentUserRole?: string;\n}\n\nexport const useChannelSettings = ({ channel, isOpen, onClose, currentUserRole }: UseChannelSettingsOptions) => {\n const [slowMode, setSlowMode] = useState<number>(0);\n const [topicsEnabled, setTopicsEnabled] = useState<boolean>(false);\n const [capabilities, setCapabilities] = useState<Record<string, boolean>>({\n 'send-message': true,\n 'send-links': true,\n 'update-own-message': true,\n 'delete-own-message': true,\n 'send-reaction': true,\n 'pin-message': true,\n 'create-poll': true,\n 'vote-poll': true,\n });\n\n const [keywords, setKeywords] = useState<string[]>([]);\n const [newKeyword, setNewKeyword] = useState('');\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const isOwner = currentUserRole === 'owner';\n\n // Sync state when panel opens or channel updates\n useEffect(() => {\n if (!channel) return;\n\n const syncData = (dataToSync = channel.data) => {\n setSlowMode((dataToSync?.member_message_cooldown as number) || 0);\n setKeywords((dataToSync?.filter_words as string[]) || []);\n setTopicsEnabled(dataToSync?.topics_enabled === true);\n\n const caps = dataToSync?.member_capabilities as string[] || [];\n setCapabilities({\n 'send-message': caps.includes('send-message'),\n 'send-links': caps.includes('send-links'),\n 'update-own-message': caps.includes('update-own-message'),\n 'delete-own-message': caps.includes('delete-own-message'),\n 'send-reaction': caps.includes('send-reaction'),\n 'pin-message': caps.includes('pin-message'),\n 'create-poll': caps.includes('create-poll'),\n 'vote-poll': caps.includes('vote-poll'),\n });\n setError(null);\n };\n\n if (isOpen) {\n syncData();\n }\n\n // Listen to real-time changes\n const subscription = channel.on('channel.updated', (event: any) => {\n const latestData = event?.channel || channel.data;\n // Force mutating local channel.data to ensure future syncData hits cache\n if (event?.channel && channel.data) {\n Object.assign(channel.data, event.channel);\n }\n\n if (isOpen) {\n syncData(latestData);\n }\n });\n\n return () => {\n subscription?.unsubscribe();\n };\n }, [isOpen, channel]);\n\n const toggleCapability = useCallback((key: string) => {\n setCapabilities(prev => ({ ...prev, [key]: !prev[key] }));\n }, []);\n\n // Compute dirty state\n const isSlowModeChanged = slowMode !== ((channel?.data?.member_message_cooldown as number) || 0);\n const isTopicsChanged = topicsEnabled !== (channel?.data?.topics_enabled === true);\n\n const currentKeywordsSorted = [...keywords].sort().join(',');\n const originalKeywordsSorted = [...((channel?.data?.filter_words as string[]) || [])].sort().join(',');\n const isKeywordsChanged = currentKeywordsSorted !== originalKeywordsSorted;\n\n const originalCapabilities = channel?.data?.member_capabilities as string[] || [];\n const initialCapabilities: Record<string, boolean> = {\n 'send-message': originalCapabilities.includes('send-message'),\n 'send-links': originalCapabilities.includes('send-links'),\n 'update-own-message': originalCapabilities.includes('update-own-message'),\n 'delete-own-message': originalCapabilities.includes('delete-own-message'),\n 'send-reaction': originalCapabilities.includes('send-reaction'),\n 'pin-message': originalCapabilities.includes('pin-message'),\n 'create-poll': originalCapabilities.includes('create-poll'),\n 'vote-poll': originalCapabilities.includes('vote-poll'),\n };\n const isCapabilitiesChanged = Object.keys(capabilities).some(k => capabilities[k] !== initialCapabilities[k]);\n\n const isDirty = isSlowModeChanged || isKeywordsChanged || isCapabilitiesChanged || isTopicsChanged;\n\n const handleAddNewKeyword = useCallback(() => {\n if (newKeyword.trim()) {\n const keyword = newKeyword.trim().toLowerCase();\n if (!keywords.includes(keyword)) {\n setKeywords(prev => [...prev, keyword]);\n }\n setNewKeyword('');\n }\n }, [newKeyword, keywords]);\n\n const handleRemoveKeyword = useCallback((kw: string) => {\n setKeywords(prev => prev.filter(k => k !== kw));\n }, []);\n\n const handleSave = useCallback(async () => {\n if (!channel) return;\n setIsSaving(true);\n setError(null);\n try {\n const dataUpdates: any = {};\n let capabilitiesArray: string[] | null = null;\n\n if (isSlowModeChanged) {\n dataUpdates.member_message_cooldown = slowMode;\n }\n\n if (isKeywordsChanged) {\n dataUpdates.filter_words = keywords;\n }\n\n if (isCapabilitiesChanged) {\n const controlledKeys = Object.keys(capabilities);\n const originalCaps = (channel.data?.member_capabilities as string[]) || [];\n\n // Preserve unmanaged original capabilities\n const unmanagedCaps = originalCaps.filter(c => !controlledKeys.includes(c));\n\n // Extract managed capabilities that are currently enabled\n const managedEnabledCaps = controlledKeys.filter(k => capabilities[k as keyof typeof capabilities]);\n\n // Merge into the final payload array\n capabilitiesArray = [...unmanagedCaps, ...managedEnabledCaps];\n }\n\n if (Object.keys(dataUpdates).length > 0 || capabilitiesArray !== null) {\n const payload: any = {};\n\n if (Object.keys(dataUpdates).length > 0) {\n payload.data = dataUpdates;\n if (channel.data) Object.assign(channel.data, dataUpdates);\n }\n\n if (capabilitiesArray !== null) {\n payload.capabilities = capabilitiesArray;\n if (channel.data) {\n channel.data.member_capabilities = capabilitiesArray;\n }\n }\n\n // Use _update instead of update to safely construct root-level payloads\n await (channel as any)._update(payload);\n }\n\n if (isTopicsChanged) {\n if (topicsEnabled) {\n await channel.enableTopics();\n } else {\n await channel.disableTopics();\n }\n }\n\n if (onClose) onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update settings');\n } finally {\n setIsSaving(false);\n }\n }, [\n channel,\n isSlowModeChanged,\n slowMode,\n isKeywordsChanged,\n keywords,\n isCapabilitiesChanged,\n capabilities,\n isTopicsChanged,\n topicsEnabled,\n onClose,\n ]);\n\n return {\n slowMode,\n setSlowMode,\n topicsEnabled,\n setTopicsEnabled,\n capabilities,\n toggleCapability,\n keywords,\n newKeyword,\n setNewKeyword,\n handleAddNewKeyword,\n handleRemoveKeyword,\n isSaving,\n error,\n isDirty,\n isOwner,\n handleSave,\n };\n};\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal as DefaultModal } from './Modal';\nimport { UserPicker } from './UserPicker';\nimport { Avatar } from './Avatar';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChatComponents } from '../context/ChatComponentsContext';\nimport { markChannelAsFullyQueried } from '../hooks/useChannelMessages';\nimport type { CreateChannelE2eeToggleProps, CreateChannelModalProps, UserPickerUser } from '../types';\nimport { isDirectChannel } from '../channelTypeUtils';\n\nconst DefaultE2eeToggle: React.FC<CreateChannelE2eeToggleProps> = ({\n enabled,\n onChange,\n disabled,\n label = 'End-to-end encrypted',\n description,\n}) => (\n <div className=\"ermis-create-channel__field ermis-create-channel__field--toggle\">\n <div>\n <label className=\"ermis-create-channel__label\">{label}</label>\n {description && <div className=\"ermis-create-channel__hint\">{description}</div>}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={enabled}\n className={`ermis-create-channel__toggle ${enabled ? 'ermis-create-channel__toggle--on' : ''}`}\n onClick={() => onChange(!enabled)}\n disabled={disabled}\n >\n <span className=\"ermis-create-channel__toggle-thumb\" />\n </button>\n </div>\n);\n\nexport const CreateChannelModal: React.FC<CreateChannelModalProps> = ({\n isOpen,\n onClose,\n onSuccess,\n AvatarComponent = Avatar,\n UserItemComponent,\n title = 'New Message',\n directTabLabel = 'Direct',\n groupTabLabel = 'Group',\n groupNameLabel = 'Channel Name',\n groupNamePlaceholder = 'Enter channel name (required)',\n groupDescriptionLabel = 'Description',\n groupDescriptionPlaceholder = 'Optional description',\n groupPublicLabel = 'Public Channel',\n userSearchPlaceholder = 'Search users...',\n cancelButtonLabel = 'Cancel',\n createButtonLabel = 'Create',\n creatingButtonLabel = 'Creating...',\n messageButtonLabel = 'Message',\n nextButtonLabel = 'Next',\n backButtonLabel = 'Back',\n emptyStateLabel = 'No users found',\n e2eeLabel = 'End-to-end encrypted',\n e2eeDescription = 'Only channel members can read encrypted messages.',\n e2eeUnavailableLabel = 'E2EE is unavailable on this device.',\n e2eeRecoveryPolicy = 'member_assisted',\n TabsComponent,\n FooterComponent,\n GroupFieldsComponent,\n SearchInputComponent,\n SelectedBoxComponent,\n E2eeToggleComponent = DefaultE2eeToggle,\n}) => {\n const { client, setActiveChannel } = useChatClient();\n const { ModalComponent } = useChatComponents();\n const Modal = ModalComponent || DefaultModal;\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [tab, setTab] = useState<'messaging' | 'team'>('messaging');\n const [step, setStep] = useState<1 | 2>(1); // Only for team channel\n\n // Group specific\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [isPublic, setIsPublic] = useState(false);\n const [e2eeEnabled, setE2eeEnabled] = useState(false);\n\n // Users\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n\n // Progress/Error\n const [isCreating, setIsCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const e2eeAvailable = Boolean(client?.encryptionManager?.initialized);\n\n const handleE2eeChange = useCallback((enabled: boolean) => {\n setE2eeEnabled(enabled);\n }, []);\n\n /* ---------- Exclude IDs for Direct ---------- */\n const hasExistingDirectChannel = useMemo(() => {\n if (!client || !currentUserId || tab !== 'messaging' || selectedUsers.length === 0) return false;\n const targetUserId = selectedUsers[0].id;\n\n return Object.values(client.activeChannels).some((ch: any) => {\n if (isDirectChannel(ch) && ch.state?.members) {\n const membersList = Object.keys(ch.state.members);\n return membersList.length === 2 &&\n membersList.includes(currentUserId) &&\n membersList.includes(targetUserId);\n }\n return false;\n });\n }, [client, currentUserId, tab, selectedUsers]);\n\n /* ---------- Handlers ---------- */\n const handleCreate = useCallback(async () => {\n if (!client || !currentUserId || isCreating) return;\n\n // Validations\n if (selectedUsers.length === 0) {\n setError('Please select at least one user.');\n return;\n }\n\n if (tab === 'team' && !name.trim()) {\n setError('Group name is required.');\n return;\n }\n\n setIsCreating(true);\n setError(null);\n\n try {\n let createdChannel;\n\n if (tab === 'messaging') {\n const targetUserId = selectedUsers[0].id;\n\n // Try to find an existing direct channel locally\n const existingChannel = Object.values(client.activeChannels).find((ch: any) => {\n if (isDirectChannel(ch) && ch.state?.members) {\n const membersList = Object.keys(ch.state.members);\n return membersList.length === 2 &&\n membersList.includes(currentUserId) &&\n membersList.includes(targetUserId);\n }\n return false;\n });\n\n if (existingChannel) {\n if (setActiveChannel) setActiveChannel(existingChannel as any);\n if (onSuccess) {\n onSuccess(existingChannel as any);\n } else {\n onClose();\n }\n setIsCreating(false);\n return;\n }\n\n const members = [currentUserId, targetUserId];\n const payload: Record<string, any> = { members };\n\n if (e2eeEnabled) {\n const encryptionManager = client.encryptionManager;\n if (!encryptionManager?.initialized) {\n throw new Error(e2eeUnavailableLabel);\n }\n const bundle = await encryptionManager.createE2eeChannel('messaging', null, null, members);\n Object.assign(payload, {\n mls_enabled: true,\n e2ee_recovery_policy: e2eeRecoveryPolicy,\n channel_id: bundle.channel_id,\n ...bundle,\n });\n }\n\n createdChannel = client.channel('messaging', payload as any);\n const response = (await createdChannel.create()) as any;\n if (response?.channel?.id) {\n createdChannel = client.channel('messaging', response.channel.id);\n await createdChannel.watch({ messages: { limit: 25, include_hidden_messages: true } });\n markChannelAsFullyQueried(createdChannel.cid);\n if (e2eeEnabled && client.encryptionManager?.initialized && createdChannel.id) {\n client.encryptionManager.archiveCurrentEpoch(createdChannel.type, createdChannel.id)\n .catch((err: unknown) => console.warn('[E2EE] Initial epoch archive failed:', err));\n }\n }\n } else {\n // Group Channel\n const memberIds = selectedUsers.map(member => member.id);\n // Ensure current user is in the group members\n if (!memberIds.includes(currentUserId)) {\n memberIds.push(currentUserId);\n }\n\n const payload: any = {\n name: name.trim(),\n members: memberIds,\n public: isPublic,\n };\n\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n if (e2eeEnabled) {\n const encryptionManager = client.encryptionManager;\n if (!encryptionManager?.initialized) {\n throw new Error(e2eeUnavailableLabel);\n }\n const uuid =\n typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n const channelId = `${client.projectId}:${uuid}`;\n const cid = `team:${channelId}`;\n const bundle = await encryptionManager.createE2eeChannel('team', channelId, cid, memberIds);\n Object.assign(payload, {\n mls_enabled: true,\n e2ee_recovery_policy: e2eeRecoveryPolicy,\n ...bundle,\n });\n createdChannel = client.channel('team', channelId, payload);\n } else {\n createdChannel = client.channel('team', payload);\n }\n const response = (await createdChannel.create()) as any;\n if (response?.channel?.id) {\n createdChannel = client.channel('team', response.channel.id);\n await createdChannel.watch({ messages: { limit: 25, include_hidden_messages: true } });\n markChannelAsFullyQueried(createdChannel.cid);\n if (e2eeEnabled && client.encryptionManager?.initialized && createdChannel.id) {\n client.encryptionManager.archiveCurrentEpoch(createdChannel.type, createdChannel.id)\n .catch((err: unknown) => console.warn('[E2EE] Initial epoch archive failed:', err));\n }\n }\n }\n\n if (setActiveChannel) {\n setActiveChannel(createdChannel);\n }\n\n // Cleanup and execute callback\n if (onSuccess) {\n onSuccess(createdChannel);\n } else {\n onClose();\n }\n\n } catch (err: any) {\n setError(err?.message || 'Failed to create channel');\n } finally {\n setIsCreating(false);\n }\n }, [\n client,\n currentUserId,\n isCreating,\n selectedUsers,\n tab,\n name,\n isPublic,\n description,\n e2eeEnabled,\n e2eeRecoveryPolicy,\n e2eeUnavailableLabel,\n onSuccess,\n onClose,\n ]);\n\n\n const isValid = useMemo(() => {\n if (tab === 'messaging' && selectedUsers.length === 0) return false;\n if (tab === 'team' && step === 1 && !name.trim()) return false;\n if (tab === 'team' && step === 2 && selectedUsers.length === 0) return false;\n return true;\n }, [selectedUsers, tab, name, step]);\n\n let footer;\n if (FooterComponent) {\n footer = (\n <FooterComponent\n tab={tab}\n step={step}\n onCancel={() => {\n if (tab === 'team' && step === 2) {\n setError(null);\n setStep(1);\n } else {\n onClose();\n }\n }}\n onNext={() => {\n setError(null);\n setStep(2);\n }}\n onBack={() => {\n setError(null);\n setStep(1);\n }}\n onCreate={handleCreate}\n isCreating={isCreating}\n isValid={isValid}\n hasExistingDirectChannel={hasExistingDirectChannel}\n cancelButtonLabel={cancelButtonLabel}\n createButtonLabel={createButtonLabel}\n creatingButtonLabel={creatingButtonLabel}\n messageButtonLabel={messageButtonLabel}\n nextButtonLabel={nextButtonLabel}\n backButtonLabel={backButtonLabel}\n e2eeEnabled={e2eeEnabled}\n />\n );\n } else if (tab === 'messaging') {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : (hasExistingDirectChannel ? messageButtonLabel : createButtonLabel)}\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 1) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={() => { setError(null); setStep(2); }} disabled={isCreating || !isValid}>\n {nextButtonLabel}\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 2) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={() => { setError(null); setStep(1); }} disabled={isCreating}>{backButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : createButtonLabel}\n </button>\n </div>\n );\n }\n\n return (\n <Modal isOpen={isOpen} onClose={isCreating ? () => { } : onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <div className=\"ermis-create-channel__body\">\n\n {/* Type Toggle */}\n {TabsComponent ? (\n <TabsComponent\n activeTab={tab}\n onTabChange={(t) => {\n setTab(t);\n setStep(1);\n setSelectedUsers([]);\n setE2eeEnabled(false);\n setError(null);\n }}\n disabled={isCreating}\n directTabLabel={directTabLabel}\n groupTabLabel={groupTabLabel}\n />\n ) : (\n <div className=\"ermis-create-channel__tabs\">\n <button\n className={`ermis-create-channel__tab ${tab === 'messaging' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('messaging');\n setStep(1);\n setSelectedUsers([]);\n setE2eeEnabled(false);\n setError(null);\n }}\n disabled={isCreating}\n >\n {directTabLabel}\n </button>\n <button\n className={`ermis-create-channel__tab ${tab === 'team' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('team');\n setStep(1);\n setSelectedUsers([]);\n setE2eeEnabled(false);\n setError(null);\n }}\n disabled={isCreating}\n >\n {groupTabLabel}\n </button>\n </div>\n )}\n\n {/* Group Specific Fields - Step 1 */}\n {tab === 'team' && step === 1 && (\n GroupFieldsComponent ? (\n <GroupFieldsComponent\n name={name}\n onNameChange={setName}\n description={description}\n onDescriptionChange={setDescription}\n isPublic={isPublic}\n onPublicChange={setIsPublic}\n disabled={isCreating}\n groupNameLabel={groupNameLabel}\n groupNamePlaceholder={groupNamePlaceholder}\n groupDescriptionLabel={groupDescriptionLabel}\n groupDescriptionPlaceholder={groupDescriptionPlaceholder}\n groupPublicLabel={groupPublicLabel}\n e2eeEnabled={e2eeEnabled}\n onE2eeChange={handleE2eeChange}\n e2eeLabel={e2eeLabel}\n e2eeDescription={e2eeDescription}\n e2eeDisabled={!e2eeAvailable || isCreating}\n />\n ) : (\n <>\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupNameLabel} <span style={{ color: 'var(--ermis-error)' }}>*</span></label>\n <input\n className=\"ermis-create-channel__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={groupNamePlaceholder}\n disabled={isCreating}\n maxLength={100}\n />\n </div>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupDescriptionLabel}</label>\n <textarea\n className=\"ermis-create-channel__textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={groupDescriptionPlaceholder}\n disabled={isCreating}\n maxLength={500}\n rows={2}\n />\n </div>\n\n <div className=\"ermis-create-channel__field ermis-create-channel__field--toggle\">\n <label className=\"ermis-create-channel__label\">{groupPublicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-create-channel__toggle ${isPublic ? 'ermis-create-channel__toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isCreating}\n >\n <span className=\"ermis-create-channel__toggle-thumb\" />\n </button>\n </div>\n\n <DefaultE2eeToggle\n enabled={e2eeEnabled}\n onChange={handleE2eeChange}\n disabled={!e2eeAvailable || isCreating}\n label={e2eeLabel}\n description={e2eeAvailable ? e2eeDescription : e2eeUnavailableLabel}\n />\n </>\n )\n )}\n\n {tab === 'messaging' && (\n <E2eeToggleComponent\n enabled={e2eeEnabled}\n onChange={handleE2eeChange}\n disabled={!e2eeAvailable || isCreating}\n label={e2eeLabel}\n description={e2eeAvailable ? e2eeDescription : e2eeUnavailableLabel}\n />\n )}\n\n {/* User Selection - Step 2 (Group) or Step 1 (Messaging) */}\n {((tab === 'team' && step === 2) || tab === 'messaging') && (\n <div className={`ermis-create-channel__users ermis-create-channel__users--${tab}`}>\n <UserPicker\n key={tab}\n mode={tab === 'messaging' ? 'radio' : 'checkbox'}\n friendsOnly={tab === 'team'}\n onSelectionChange={setSelectedUsers}\n initialSelectedUsers={selectedUsers}\n emptyText={emptyStateLabel}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n SearchInputComponent={SearchInputComponent as any}\n SelectedBoxComponent={SelectedBoxComponent as any}\n searchPlaceholder={userSearchPlaceholder}\n />\n </div>\n )}\n\n {error && (\n <div className=\"ermis-create-channel__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n\n </div>\n </Modal>\n );\n};\n","import React, { useMemo, useState } from 'react';\n\nimport { useRecoveryPin } from '../../hooks/useRecoveryPin';\nimport type { RecoveryPinStatus } from '../../hooks/useRecoveryPin';\n\nexport type RecoveryPinSetupProps = {\n onComplete?: () => void;\n minDigits?: number;\n};\n\nexport type RecoveryPinRestoreProps = {\n onComplete?: () => void;\n};\n\nexport type RecoveryPinChangeProps = {\n onComplete?: () => void;\n minDigits?: number;\n};\n\nexport type RecoveryStatusProps = {\n status?: RecoveryPinStatus;\n hasRecoveryKey?: boolean;\n className?: string;\n};\n\nexport type RecoveryGapProps = {\n epoch?: number;\n reason: string;\n className?: string;\n};\n\nexport type RecoveryGateProps = {\n onSkip?: () => void;\n className?: string;\n};\n\nexport type RecoveryRestoreProgressProps = {\n restoredEpochs: number;\n totalEpochs: number;\n gaps?: Array<{ epoch?: number; reason: string }>;\n className?: string;\n};\n\nconst MIN_PIN_DIGITS = 8;\n\nconst pinError = (pin: string, minDigits = MIN_PIN_DIGITS): string | null => {\n if (!/^\\d+$/.test(pin)) return 'PIN must contain digits only.';\n if (pin.length < minDigits) return `PIN must be at least ${minDigits} digits.`;\n return null;\n};\n\nconst bruteForceLabel = (digits: number): string => {\n if (digits >= 10) return 'Strong';\n if (digits >= 8) return 'Medium';\n return 'Weak';\n};\n\nexport const RecoveryPinSetup: React.FC<RecoveryPinSetupProps> = ({\n onComplete,\n minDigits = MIN_PIN_DIGITS,\n}) => {\n const recovery = useRecoveryPin();\n const [pin, setPin] = useState('');\n const [confirmPin, setConfirmPin] = useState('');\n const validation = pin ? pinError(pin, minDigits) : null;\n const mismatch = confirmPin && pin !== confirmPin ? 'PIN confirmation does not match.' : null;\n const canSubmit = !!pin && !!confirmPin && !validation && !mismatch && recovery.status !== 'working';\n\n const submit = async (event: React.FormEvent) => {\n event.preventDefault();\n if (!canSubmit) return;\n await recovery.setupRecoveryPin(pin);\n onComplete?.();\n };\n\n return (\n <form className=\"ermis-recovery-pin\" onSubmit={submit}>\n <div className=\"ermis-recovery-pin__header\">\n <h3>Recovery PIN</h3>\n <span className=\"ermis-recovery-pin__badge\">{bruteForceLabel(pin.length)}</span>\n </div>\n <input\n className=\"ermis-recovery-pin__input\"\n inputMode=\"numeric\"\n autoComplete=\"new-password\"\n type=\"password\"\n value={pin}\n onChange={(event) => setPin(event.target.value)}\n placeholder=\"Enter PIN\"\n />\n <input\n className=\"ermis-recovery-pin__input\"\n inputMode=\"numeric\"\n autoComplete=\"new-password\"\n type=\"password\"\n value={confirmPin}\n onChange={(event) => setConfirmPin(event.target.value)}\n placeholder=\"Confirm PIN\"\n />\n {(validation || mismatch || recovery.error) && (\n <div className=\"ermis-recovery-pin__error\">\n {validation || mismatch || recovery.error?.message}\n </div>\n )}\n <button className=\"ermis-recovery-pin__button\" type=\"submit\" disabled={!canSubmit}>\n {recovery.status === 'working' ? 'Saving...' : 'Save PIN'}\n </button>\n </form>\n );\n};\n\nexport const RecoveryPinRestore: React.FC<RecoveryPinRestoreProps> = ({ onComplete }) => {\n const recovery = useRecoveryPin();\n const [pin, setPin] = useState('');\n const validation = pin ? pinError(pin) : null;\n const canSubmit = !!pin && !validation && recovery.status !== 'working';\n\n const submit = async (event: React.FormEvent) => {\n event.preventDefault();\n if (!canSubmit) return;\n await recovery.unlockRecoveryVault(pin);\n onComplete?.();\n };\n\n return (\n <form className=\"ermis-recovery-pin\" onSubmit={submit}>\n <div className=\"ermis-recovery-pin__header\">\n <h3>Unlock History</h3>\n </div>\n <input\n className=\"ermis-recovery-pin__input\"\n inputMode=\"numeric\"\n autoComplete=\"current-password\"\n type=\"password\"\n value={pin}\n onChange={(event) => setPin(event.target.value)}\n placeholder=\"Enter recovery PIN\"\n />\n {(validation || recovery.error) && (\n <div className=\"ermis-recovery-pin__error\">{validation || recovery.error?.message}</div>\n )}\n <button className=\"ermis-recovery-pin__button\" type=\"submit\" disabled={!canSubmit}>\n {recovery.status === 'working' ? 'Unlocking...' : 'Unlock'}\n </button>\n </form>\n );\n};\n\nexport const RecoveryPinChange: React.FC<RecoveryPinChangeProps> = ({\n onComplete,\n minDigits = MIN_PIN_DIGITS,\n}) => {\n const recovery = useRecoveryPin();\n const [oldPin, setOldPin] = useState('');\n const [newPin, setNewPin] = useState('');\n const validation = newPin ? pinError(newPin, minDigits) : null;\n const canSubmit = !!oldPin && !!newPin && !validation && recovery.status !== 'working';\n\n const submit = async (event: React.FormEvent) => {\n event.preventDefault();\n if (!canSubmit) return;\n await recovery.changeRecoveryPin(oldPin, newPin);\n onComplete?.();\n };\n\n return (\n <form className=\"ermis-recovery-pin\" onSubmit={submit}>\n <div className=\"ermis-recovery-pin__header\">\n <h3>Change Recovery PIN</h3>\n <span className=\"ermis-recovery-pin__badge\">{bruteForceLabel(newPin.length)}</span>\n </div>\n <input\n className=\"ermis-recovery-pin__input\"\n inputMode=\"numeric\"\n autoComplete=\"current-password\"\n type=\"password\"\n value={oldPin}\n onChange={(event) => setOldPin(event.target.value)}\n placeholder=\"Current PIN\"\n />\n <input\n className=\"ermis-recovery-pin__input\"\n inputMode=\"numeric\"\n autoComplete=\"new-password\"\n type=\"password\"\n value={newPin}\n onChange={(event) => setNewPin(event.target.value)}\n placeholder=\"New PIN\"\n />\n {(validation || recovery.error) && (\n <div className=\"ermis-recovery-pin__error\">{validation || recovery.error?.message}</div>\n )}\n <button className=\"ermis-recovery-pin__button\" type=\"submit\" disabled={!canSubmit}>\n {recovery.status === 'working' ? 'Changing...' : 'Change PIN'}\n </button>\n </form>\n );\n};\n\nexport const RecoveryStatus: React.FC<RecoveryStatusProps> = ({\n status,\n hasRecoveryKey,\n className,\n}) => {\n const recovery = useRecoveryPin();\n const resolvedStatus = status || recovery.status;\n const resolvedHasKey = hasRecoveryKey ?? recovery.hasRecoveryKey;\n const label = useMemo(() => {\n if (resolvedStatus === 'working') return 'Recovery syncing';\n if (resolvedStatus === 'error') return 'Recovery error';\n if (recovery.recoveryStatus?.hasIncompleteRestore) return 'Recovery pending';\n if ((recovery.recoveryStatus?.channelsWithPermanentGaps.length || 0) > 0) return 'Recovery has gaps';\n return resolvedHasKey ? 'Recovery ready' : 'Recovery locked';\n }, [recovery.recoveryStatus, resolvedHasKey, resolvedStatus]);\n\n return (\n <span className={`ermis-recovery-status ermis-recovery-status--${resolvedStatus}${className ? ` ${className}` : ''}`}>\n {label}\n </span>\n );\n};\n\nexport const RecoveryGap: React.FC<RecoveryGapProps> = ({ epoch, reason, className }) => (\n <div className={`ermis-recovery-gap${className ? ` ${className}` : ''}`}>\n {epoch !== undefined ? `Epoch ${epoch}: ` : ''}{reason}\n </div>\n);\n\nexport const RecoveryGate: React.FC<RecoveryGateProps> = ({ onSkip, className }) => {\n const recovery = useRecoveryPin();\n const [skipped, setSkipped] = useState(false);\n const status = recovery.recoveryStatus;\n if (skipped || !status) return null;\n\n const skip = () => {\n setSkipped(true);\n onSkip?.();\n };\n\n if (!status.hasVault) {\n return (\n <div className={`ermis-recovery-gate${className ? ` ${className}` : ''}`} role=\"dialog\" aria-modal=\"true\">\n <RecoveryPinSetup onComplete={recovery.refresh} />\n <button className=\"ermis-recovery-pin__button ermis-recovery-pin__button--secondary\" type=\"button\" onClick={skip}>\n Skip\n </button>\n </div>\n );\n }\n\n if (!status.unlocked && status.hasIncompleteRestore) {\n return (\n <div className={`ermis-recovery-gate${className ? ` ${className}` : ''}`} role=\"dialog\" aria-modal=\"true\">\n <RecoveryPinRestore onComplete={recovery.refresh} />\n <button className=\"ermis-recovery-pin__button ermis-recovery-pin__button--secondary\" type=\"button\" onClick={skip}>\n Skip\n </button>\n </div>\n );\n }\n\n return null;\n};\n\nexport const RecoveryRestoreProgress: React.FC<RecoveryRestoreProgressProps> = ({\n restoredEpochs,\n totalEpochs,\n gaps = [],\n className,\n}) => (\n <div className={`ermis-recovery-progress${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-recovery-progress__summary\">\n {restoredEpochs}/{totalEpochs} epochs restored\n </div>\n {gaps.map((gap, index) => (\n <RecoveryGap key={`${gap.epoch ?? 'gap'}-${index}`} epoch={gap.epoch} reason={gap.reason} />\n ))}\n </div>\n);\n"],"mappings":"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","names":["createContext","useState","useCallback","useRef","React","useEffect","useRef","useState","useCallback","useEffect","jsx","React","useMemo","useState","React","useState","useEffect","useCallback","useRef","React","React","useCallback","useContext","useContext","useCallback","jsx","jsxs","React","useState","useRef","useEffect","useCallback","jsx","jsxs","React","useState","useMemo","useContext","CallStatus","Fragment","jsx","jsxs","React","Modal","useRef","useState","useCallback","useEffect","jsx","jsxs","createContext","useState","useRef","useCallback","useState","useEffect","useState","useEffect","useEffect","useState","useMemo","useState","useEffect","useMemo","useEffect","useState","useMemo","useCallback","useState","useCallback","useEffect","useMemo","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useState","useEffect","useRef","useRef","useEffect","ch","useEffect","useState","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useMemo","useMemo","useState","useEffect","useState","useEffect","useMemo","useRef","useMemo","useState","useRef","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useMemo","useCallback","useState","useCallback","useEffect","useMemo","useState","useEffect","useCallback","useRef","useState","useCallback","useRef","isE2eeChannel","message","errorFiles","useState","useCallback","useRef","isE2eeChannel","useCallback","useState","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useState","useCallback","useRef","useState","useRef","useCallback","useState","useEffect","useCallback","useState","useEffect","useCallback","useState","useEffect","useCallback","useState","useEffect","useMemo","React","useEffect","useRef","useState","useCallback","useMemo","React","useState","useCallback","jsx","jsxs","React","Modal","useState","useCallback","React","useState","useCallback","useEffect","useRef","jsx","Fragment","jsx","jsxs","hasTopicsEnabled","React","useState","useCallback","React","useCallback","useMemo","jsx","jsxs","React","useMemo","useCallback","jsx","jsxs","React","useState","useEffect","useMemo","useCallback","useRef","React","useState","useRef","useEffect","useCallback","useMemo","_VList","Fragment","jsx","jsxs","VList","_VList","React","useRef","useEffect","useState","useCallback","useMemo","client","React","useEffect","useMemo","useState","React","useEffect","useCallback","useRef","useState","useMemo","useCallback","useState","useMemo","useCallback","Fragment","jsx","jsxs","React","Modal","useRef","useEffect","useCallback","jsx","jsxs","DefaultEmpty","React","useState","useEffect","useMemo","React","useMemo","useState","useEffect","useContext","Fragment","jsx","jsxs","React","useContext","useState","useEffect","useMemo","React","useRef","useCallback","useMemo","useEffect","useLayoutEffect","_VList","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","useState","useEffect","useCallback","useRef","formatMessage","useState","useRef","useEffect","useCallback","formatMessage","useEffect","useCallback","useRef","useRef","useCallback","useEffect","stored","React","React","useMemo","jsx","jsxs","React","useMemo","React","useCallback","useMemo","useMemo","React","useCallback","useState","useRef","useEffect","jsx","jsxs","React","useState","useRef","useEffect","useCallback","Fragment","jsx","jsxs","Dropdown","React","useCallback","jsxs","Fragment","jsx","React","createPortal","jsx","jsxs","React","Fragment","jsx","jsxs","React","React","useState","useMemo","useCallback","useEffect","useRef","parseSystemMessage","parseSignalMessage","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useMemo","isE2eeAttachmentManifest","formatFileSize","useRef","useEffect","useCallback","jsxs","jsx","useState","React","useCallback","useMemo","isE2eeAttachmentManifest","Fragment","parseSystemMessage","parseSignalMessage","isAudio","React","useState","useEffect","useMemo","useCallback","jsx","jsxs","React","useMemo","useState","useEffect","useCallback","React","jsx","jsxs","React","React","useState","useEffect","useRef","useState","useRef","useEffect","jsx","jsxs","React","React","jsx","jsxs","React","jsx","jsxs","React","jsx","jsxs","React","jsx","jsxs","Fragment","jsx","jsxs","VList","_VList","React","DefaultEmpty","useRef","useMemo","useCallback","useEffect","useLayoutEffect","React","useState","useCallback","useMemo","useEffect","useRef","useState","useCallback","useMemo","useState","useMemo","useCallback","React","useState","useRef","useEffect","jsx","jsxs","formatTime","React","useEffect","useRef","jsx","jsxs","React","useRef","useEffect","React","isHeicFile","jsx","jsxs","formatFileSize","getFileIcon","isImage","isVideo","React","useMemo","jsx","jsxs","MAX_PREVIEW_LENGTH","truncateText","React","useMemo","React","useMemo","jsx","jsxs","MAX_PREVIEW_LENGTH","truncateText","getAttachmentSummary","React","useMemo","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useRef","useEffect","useCallback","useMemo","useCallback","useEffect","useMemo","useState","useState","useCallback","useEffect","useMemo","React","useState","useCallback","useRef","useEffect","React","_VList","useState","useEffect","useMemo","useCallback","useRef","React","useCallback","useEffect","useRef","useState","useMemo","jsx","jsxs","useRef","useState","isVideo","isImage","useEffect","useCallback","useMemo","React","React","useState","useMemo","jsx","jsxs","React","useState","useMemo","React","jsx","jsxs","React","React","useState","Fragment","jsx","jsxs","React","useState","React","jsx","jsxs","jsx","jsxs","useMemo","useState","useRef","useCallback","useEffect","jsx","jsxs","VList","_VList","React","useState","useMemo","useCallback","React","useState","useEffect","useMemo","useCallback","useRef","_VList","jsx","jsxs","VList","_VList","React","useCallback","useState","startTransition","useRef","useMemo","useEffect","jsx","Modal","useState","useMemo","useCallback","React","useState","useRef","useCallback","useEffect","jsx","jsxs","React","Modal","useState","useRef","useEffect","useCallback","React","useRef","useCallback","useEffect","React","useEffect","useRef","jsx","jsxs","useState","useEffect","useRef","useCallback","useMemo","useState","useRef","useEffect","useCallback","useMemo","Fragment","jsx","jsxs","React","Panel","useRef","useEffect","useCallback","React","useState","useEffect","useCallback","jsx","jsxs","React","Panel","Fragment","jsx","jsxs","React","PinIcon","UnpinIcon","LeaveIcon","BlockIcon","useRef","useState","useCallback","useEffect","useState","useMemo","useCallback","Fragment","jsx","jsxs","Modal","useState","useCallback","useMemo","useMemo","useState","jsx","jsxs","useState","useMemo"]}
|