@medipha/chat 1.0.14
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 +103 -0
- package/dist/api/client.d.ts +5 -0
- package/dist/features/composer/attachment-file-helpers.d.ts +22 -0
- package/dist/features/composer/attachments/attachment-buttons.d.ts +8 -0
- package/dist/features/composer/conversation-composer.d.ts +20 -0
- package/dist/features/composer/editor/font-size-extension.d.ts +18 -0
- package/dist/features/composer/editor/mention-suggestion-list.d.ts +15 -0
- package/dist/features/composer/editor/paste-text-style.d.ts +5 -0
- package/dist/features/composer/emoji/emoji-picker-button.d.ts +9 -0
- package/dist/features/composer/emoji/emoji-shortcode-extension.d.ts +9 -0
- package/dist/features/composer/emoji/emoji-shortcodes.d.ts +2 -0
- package/dist/features/composer/format-bar/format-bar.d.ts +14 -0
- package/dist/features/composer/more-menu/more-menu.d.ts +4 -0
- package/dist/features/composer/pending-attachment.d.ts +10 -0
- package/dist/features/composer/reply/composer-reply-banner.d.ts +11 -0
- package/dist/features/composer/reply/use-reply-target.d.ts +12 -0
- package/dist/features/composer/stickers.d.ts +6 -0
- package/dist/features/composer/toolbar/composer-toolbar.d.ts +19 -0
- package/dist/features/composer/typing/use-typing-notifier.d.ts +11 -0
- package/dist/features/composer/use-attachment-upload.d.ts +4 -0
- package/dist/features/composer/use-pending-attachments.d.ts +16 -0
- package/dist/features/create-conversation/create-conversation-panel.d.ts +9 -0
- package/dist/features/create-conversation/tabs/create-group-tab.d.ts +13 -0
- package/dist/features/create-conversation/tabs/direct-chat-tab.d.ts +12 -0
- package/dist/features/create-conversation/tabs/selected-members-modal.d.ts +11 -0
- package/dist/features/files/file-attachment.d.ts +24 -0
- package/dist/features/forward/forward-dialog.d.ts +11 -0
- package/dist/features/forward/use-forward-message.d.ts +21 -0
- package/dist/features/media-preview/media-preview-modal.d.ts +23 -0
- package/dist/features/media-preview/use-image-lightbox.d.ts +16 -0
- package/dist/features/message-list/bubble/message-actions/message-actions-menu.d.ts +27 -0
- package/dist/features/message-list/bubble/message-bubble.d.ts +53 -0
- package/dist/features/message-list/bubble/message-content-body.d.ts +12 -0
- package/dist/features/message-list/bubble/message-reactions.d.ts +18 -0
- package/dist/features/message-list/bubble/rich-message-content.d.ts +8 -0
- package/dist/features/message-list/overlays/message-details/message-details-modal.d.ts +16 -0
- package/dist/features/message-list/overlays/message-details/use-message-details-modal.d.ts +14 -0
- package/dist/features/message-list/overlays/message-menu/use-message-menu.d.ts +21 -0
- package/dist/features/message-list/overlays/reaction/reaction-modal.d.ts +22 -0
- package/dist/features/message-list/overlays/reaction/use-reaction-modal.d.ts +23 -0
- package/dist/features/message-list/overlays/reaction/use-reaction-picker.d.ts +8 -0
- package/dist/features/message-list/overlays/system-members/system-members-modal.d.ts +22 -0
- package/dist/features/message-list/overlays/system-members/use-system-members-modal.d.ts +18 -0
- package/dist/features/message-list/use-message-removal.d.ts +12 -0
- package/dist/features/message-list/use-message-timeline-scroll.d.ts +25 -0
- package/dist/features/message-window/use-message-window.d.ts +46 -0
- package/dist/features/pinned-messages/pinned-messages-bar.d.ts +18 -0
- package/dist/features/pinned-messages/use-pinned-messages.d.ts +21 -0
- package/dist/features/typing/use-typing-indicator.d.ts +12 -0
- package/dist/index.cjs +278 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +66322 -0
- package/dist/module/chat-module.d.ts +3 -0
- package/dist/module/chat-module.types.d.ts +11 -0
- package/dist/module/chat-routes.d.ts +4 -0
- package/dist/module/chat-runtime-context.d.ts +5 -0
- package/dist/pages/Setting/archive/archive-attachment-preview.d.ts +13 -0
- package/dist/pages/Setting/archive/archive-file-list.d.ts +15 -0
- package/dist/pages/Setting/archive/archive-helpers.d.ts +37 -0
- package/dist/pages/Setting/archive/archive-media-grid.d.ts +14 -0
- package/dist/pages/Setting/archive/archive-view.d.ts +19 -0
- package/dist/pages/Setting/archive/hooks/use-conversation-archive.d.ts +22 -0
- package/dist/pages/Setting/conversation-settings-panel.d.ts +20 -0
- package/dist/pages/Setting/hooks/use-conversation-settings.d.ts +41 -0
- package/dist/pages/Setting/hooks/use-search-panel.d.ts +7 -0
- package/dist/pages/Setting/index.d.ts +39 -0
- package/dist/pages/Setting/members/add-member-modal.d.ts +11 -0
- package/dist/pages/Setting/members/group-members-modal.d.ts +21 -0
- package/dist/pages/Setting/members/hooks/use-rename-group-dialog.d.ts +15 -0
- package/dist/pages/Setting/members/member-selection-footer.d.ts +12 -0
- package/dist/pages/Setting/members/members-list-modal.d.ts +29 -0
- package/dist/pages/Setting/members/settings-modal.d.ts +36 -0
- package/dist/pages/Setting/members/use-member-selection.d.ts +18 -0
- package/dist/pages/Setting/search-panel.d.ts +13 -0
- package/dist/pages/conversation/conversation-detail/conversation-detail.d.ts +92 -0
- package/dist/pages/conversation/conversation-footer/conversation-footer.d.ts +42 -0
- package/dist/pages/conversation/conversation-header/conversation-header.d.ts +27 -0
- package/dist/pages/conversation/hooks/use-current-membership.d.ts +14 -0
- package/dist/pages/conversation/index.d.ts +28 -0
- package/dist/pages/conversations/empty-state/conversation-empty-state.d.ts +3 -0
- package/dist/pages/conversations/index.d.ts +4 -0
- package/dist/pages/sidebar/hooks/use-conversations.d.ts +17 -0
- package/dist/pages/sidebar/index.d.ts +4 -0
- package/dist/pages/sidebar/sidbar-conversation-list/sidbar-conversation-list.d.ts +13 -0
- package/dist/pages/sidebar/sidebar-filter/sidebar-filter.d.ts +13 -0
- package/dist/pages/sidebar/sidebar-header-infor/sidebar-header-infor.d.ts +4 -0
- package/dist/shared/components/banner-carousel.d.ts +9 -0
- package/dist/shared/components/conversation-avatar.d.ts +19 -0
- package/dist/shared/components/date-range-filter-pill.d.ts +17 -0
- package/dist/shared/components/download-action.d.ts +11 -0
- package/dist/shared/components/filter-pill.d.ts +15 -0
- package/dist/shared/components/image-not-available.d.ts +12 -0
- package/dist/shared/components/image-with-fallback.d.ts +13 -0
- package/dist/shared/components/load-more-sentinel.d.ts +15 -0
- package/dist/shared/components/quote-icon.d.ts +5 -0
- package/dist/shared/components/search-empty-state.d.ts +8 -0
- package/dist/shared/components/shared-icon.d.ts +5 -0
- package/dist/shared/components/user-avatar.d.ts +12 -0
- package/dist/shared/components/user-profile-modal.d.ts +13 -0
- package/dist/shared/components/verified-badge.d.ts +5 -0
- package/dist/shared/helper/dayjs-date-picker.d.ts +14 -0
- package/dist/shared/hooks/use-directory-filter.d.ts +13 -0
- package/dist/shared/hooks/use-user-profile-modal.d.ts +9 -0
- package/dist/socket/chatSocket.d.ts +6 -0
- package/dist/store/authStore.d.ts +34 -0
- package/dist/store/connectionStore.d.ts +8 -0
- package/dist/store/conversationsStore.d.ts +38 -0
- package/dist/store/forwardStore.d.ts +14 -0
- package/dist/store/pinnedMessagesStore.d.ts +16 -0
- package/dist/store/presenceStore.d.ts +11 -0
- package/dist/store/verifiedPermissionsStore.d.ts +20 -0
- package/dist/styles.css +2 -0
- package/dist/utils/chat-display.d.ts +44 -0
- package/dist/utils/chat-member-resolvers.d.ts +9 -0
- package/dist/utils/chat-toast.d.ts +18 -0
- package/dist/utils/chat.d.ts +282 -0
- package/dist/utils/token.d.ts +0 -0
- package/dist/utils/work-status.d.ts +15 -0
- package/package.json +96 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ChatModuleProps {
|
|
2
|
+
hasAddGroupVerified: boolean;
|
|
3
|
+
hasUpdateGroupVerified: boolean;
|
|
4
|
+
hasDeleteGroupVerified: boolean;
|
|
5
|
+
userId: string;
|
|
6
|
+
accessToken: string;
|
|
7
|
+
apiUrl: string;
|
|
8
|
+
socketUrl: string;
|
|
9
|
+
onUnauthorized?: () => void;
|
|
10
|
+
onNavigateOutsideChat?: (path: string) => void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Declares routes relative to the ERP route that mounts ChatModule. ConversationScreen
|
|
2
|
+
* itself renders the sidebar plus either the empty state or the active conversation, so
|
|
3
|
+
* the index route (no conversationId) reuses it directly. */
|
|
4
|
+
export declare function ChatRoutes(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ChatModuleProps } from './chat-module.types';
|
|
2
|
+
export type ChatRuntimeContextValue = ChatModuleProps;
|
|
3
|
+
export declare const ChatRuntimeContext: import('react').Context<ChatModuleProps | undefined>;
|
|
4
|
+
/** Returns the current ERP-provided authentication and endpoint configuration. */
|
|
5
|
+
export declare function useChatRuntime(): ChatRuntimeContextValue;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ChatMessageAttachment } from '../../../utils/chat';
|
|
2
|
+
export interface AttachmentPreviewState {
|
|
3
|
+
kind: 'image' | 'file';
|
|
4
|
+
attachment: ChatMessageAttachment;
|
|
5
|
+
}
|
|
6
|
+
interface ArchiveAttachmentPreviewProps {
|
|
7
|
+
state: AttachmentPreviewState;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
}
|
|
10
|
+
/** Full-screen image preview for the archive media grid. Documents open in a new tab via
|
|
11
|
+
* an online document viewer from their file card instead. */
|
|
12
|
+
export declare function ArchiveAttachmentPreview({ state, onClose }: ArchiveAttachmentPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ChatMessage, ChatMessageAttachment } from '../../../utils/chat';
|
|
2
|
+
import { ArchiveDayGroup, FileEntry } from './archive-helpers';
|
|
3
|
+
interface ArchiveFileListProps {
|
|
4
|
+
groups: Array<ArchiveDayGroup<FileEntry>>;
|
|
5
|
+
resolveSenderName: (senderId?: string) => string;
|
|
6
|
+
/** Kept for signature compatibility; preview is now handled inside each file card. */
|
|
7
|
+
onSelect?: (message: ChatMessage, attachment: ChatMessageAttachment) => void;
|
|
8
|
+
/** Forward this file to another conversation; omitted when sharing isn't available. */
|
|
9
|
+
onShare?: (message: ChatMessage) => void;
|
|
10
|
+
/** Jumps back to the message this file was sent in; omitted when unavailable. */
|
|
11
|
+
onJumpToMessage?: (message: ChatMessage) => void;
|
|
12
|
+
}
|
|
13
|
+
/** "Files" tab body — attachment cards grouped by day, each with preview/download/share. */
|
|
14
|
+
export declare function ArchiveFileList({ groups, resolveSenderName, onShare, onJumpToMessage }: ArchiveFileListProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ChatMessage, ChatMessageAttachment } from '../../../utils/chat';
|
|
2
|
+
/**
|
|
3
|
+
* A message can carry several attachments (e.g. a multi-image grid), which live in
|
|
4
|
+
* `attachments[]`; a single-attachment message only has the flat `attachmentId`/`attachmentUrl`
|
|
5
|
+
* fields and an empty `attachments[]`. Normalize both shapes to one list so every attachment
|
|
6
|
+
* gets its own archive entry instead of just the message's first/cover one.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getMessageAttachments(message: ChatMessage): ChatMessageAttachment[];
|
|
9
|
+
export interface FileEntry {
|
|
10
|
+
message: ChatMessage;
|
|
11
|
+
attachment: ChatMessageAttachment;
|
|
12
|
+
}
|
|
13
|
+
export declare function flattenFileEntries(messages: ChatMessage[]): FileEntry[];
|
|
14
|
+
export type FileTypeFilter = 'all' | 'word' | 'excel' | 'pdf' | 'zip' | 'other';
|
|
15
|
+
export declare const FILE_TYPE_OPTIONS: Array<{
|
|
16
|
+
value: FileTypeFilter;
|
|
17
|
+
label: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function getFileTypeCategoryByName(name: string | null | undefined): FileTypeFilter;
|
|
20
|
+
export declare function getFileTypeCategory(attachment: ChatMessageAttachment): FileTypeFilter;
|
|
21
|
+
/** Icon (label + color class) for a file by its name/extension — the archive's icon set. */
|
|
22
|
+
export declare function getFileIcon(name: string | null | undefined): {
|
|
23
|
+
label: string;
|
|
24
|
+
className: string;
|
|
25
|
+
};
|
|
26
|
+
export declare const FILE_TYPE_ICON: Record<FileTypeFilter, {
|
|
27
|
+
label: string;
|
|
28
|
+
className: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function formatSentTime(createdAt: string): string;
|
|
31
|
+
export interface ArchiveDayGroup<T> {
|
|
32
|
+
label: string;
|
|
33
|
+
items: T[];
|
|
34
|
+
}
|
|
35
|
+
export declare function groupByDay<T>(items: T[], getDate: (item: T) => string): Array<ArchiveDayGroup<T>>;
|
|
36
|
+
/** Extracts the hostname from a URL for a compact "gitlab.meditech.vn"-style subtitle. */
|
|
37
|
+
export declare function getUrlHost(url: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ChatMessage, ChatMessageAttachment } from '../../../utils/chat';
|
|
2
|
+
import { ArchiveDayGroup } from './archive-helpers';
|
|
3
|
+
interface ArchiveMediaGridProps {
|
|
4
|
+
groups: Array<ArchiveDayGroup<ChatMessage>>;
|
|
5
|
+
resolveSenderName: (senderId?: string) => string;
|
|
6
|
+
onSelect: (message: ChatMessage, attachment: ChatMessageAttachment) => void;
|
|
7
|
+
/** Forward the image to another conversation; omitted when sharing isn't available. */
|
|
8
|
+
onShare?: (message: ChatMessage) => void;
|
|
9
|
+
/** Jumps back to the message this image was sent in; omitted when unavailable. */
|
|
10
|
+
onJumpToMessage?: (message: ChatMessage) => void;
|
|
11
|
+
}
|
|
12
|
+
/** "Ảnh/Video" tab body — thumbnails grouped by day, each with preview/download/share. */
|
|
13
|
+
export declare function ArchiveMediaGrid({ groups, resolveSenderName, onSelect, onShare, onJumpToMessage, }: ArchiveMediaGridProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChatMessage, ConversationMember } from '../../../utils/chat';
|
|
2
|
+
import { ArchiveTab } from './hooks/use-conversation-archive';
|
|
3
|
+
interface ArchiveViewProps {
|
|
4
|
+
conversationId: string | undefined;
|
|
5
|
+
initialTab: ArchiveTab;
|
|
6
|
+
members: ConversationMember[];
|
|
7
|
+
onBack: () => void;
|
|
8
|
+
/** Forwards a file's message to another conversation (opens the forward picker). */
|
|
9
|
+
onForwardMessage?: (message: ChatMessage) => void;
|
|
10
|
+
/** Jumps back to the message an attachment was sent in; omitted when unavailable. */
|
|
11
|
+
onJumpToMessage?: (message: ChatMessage) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* "Kho lưu trữ": browses a conversation's media, files, and links (entire history by
|
|
15
|
+
* default), filterable by day/sender/type. Renders inline in place of the settings panel
|
|
16
|
+
* body (not an overlay modal).
|
|
17
|
+
*/
|
|
18
|
+
export declare function ArchiveView({ conversationId, initialTab, members, onBack, onForwardMessage, onJumpToMessage, }: ArchiveViewProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ChatMessage } from '../../../../utils/chat';
|
|
2
|
+
export type ArchiveTab = 'media' | 'file';
|
|
3
|
+
export interface ArchiveDateRange {
|
|
4
|
+
from?: string | null;
|
|
5
|
+
to?: string | null;
|
|
6
|
+
}
|
|
7
|
+
/** Loads media/file/link archive data for a conversation (entire history by default),
|
|
8
|
+
* filterable by sender and an explicit sent-date range. */
|
|
9
|
+
export declare function useConversationArchive(conversationId: string | undefined): {
|
|
10
|
+
error: string;
|
|
11
|
+
fileItems: ChatMessage[];
|
|
12
|
+
load: (tab: ArchiveTab, dateRange?: ArchiveDateRange) => Promise<void>;
|
|
13
|
+
loadingTab: ArchiveTab | null;
|
|
14
|
+
mediaItems: ChatMessage[];
|
|
15
|
+
senderId: string | null;
|
|
16
|
+
setSenderId: import('react').Dispatch<import('react').SetStateAction<string | null>>;
|
|
17
|
+
};
|
|
18
|
+
/** Fetches a small preview (default 5-day window) of media and file items for the settings panel. */
|
|
19
|
+
export declare function useConversationArchivePreview(conversationId: string | undefined): {
|
|
20
|
+
filePreview: ChatMessage[];
|
|
21
|
+
mediaPreview: ChatMessage[];
|
|
22
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ChatMessage, Conversation } from '../../utils/chat';
|
|
2
|
+
interface ConversationSettingsPanelProps {
|
|
3
|
+
conversation: Conversation | null;
|
|
4
|
+
conversationId: string | undefined;
|
|
5
|
+
currentUserId: string | null;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onConversationUpdated: (update: Partial<Conversation>) => void;
|
|
8
|
+
onDeleteSuccess: () => void;
|
|
9
|
+
onLeaveSuccess: () => void;
|
|
10
|
+
onMembersChanged?: () => void;
|
|
11
|
+
/** Opens (or reuses) a direct conversation with the given user. */
|
|
12
|
+
onStartChat: (userId: string) => void;
|
|
13
|
+
/** Forwards a file's message to another conversation (opens the forward picker). */
|
|
14
|
+
onForwardMessage?: (message: ChatMessage) => void;
|
|
15
|
+
/** Jumps back to the message an attachment was sent in; omitted when unavailable. */
|
|
16
|
+
onJumpToMessage?: (message: ChatMessage) => void;
|
|
17
|
+
}
|
|
18
|
+
/** Slide-over panel exposing conversation settings and membership management. */
|
|
19
|
+
export declare function ConversationSettingsPanel({ conversation, conversationId, currentUserId, onClose, onConversationUpdated, onDeleteSuccess, onLeaveSuccess, onMembersChanged, onStartChat, onForwardMessage, onJumpToMessage, }: ConversationSettingsPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Conversation, ConversationMember } from '../../../utils/chat';
|
|
2
|
+
interface UseConversationSettingsParams {
|
|
3
|
+
conversationId: string | undefined;
|
|
4
|
+
currentUserId: string | null;
|
|
5
|
+
onConversationUpdated?: (conversation: Conversation) => void;
|
|
6
|
+
onDeleteSuccess?: () => void;
|
|
7
|
+
onLeaveSuccess?: () => void;
|
|
8
|
+
onMembersChanged?: () => void;
|
|
9
|
+
}
|
|
10
|
+
/** Coordinates member management, rename, delete, and leave actions for a conversation. */
|
|
11
|
+
export declare function useConversationSettings({ conversationId, currentUserId, onConversationUpdated, onDeleteSuccess, onLeaveSuccess, onMembersChanged, }: UseConversationSettingsParams): {
|
|
12
|
+
actionError: string;
|
|
13
|
+
addingUserId: string | null;
|
|
14
|
+
addMember: (userId: string) => Promise<boolean>;
|
|
15
|
+
addMembers: (userIds: string[]) => Promise<boolean>;
|
|
16
|
+
currentMember: ConversationMember | null;
|
|
17
|
+
deletingUserId: string | null;
|
|
18
|
+
deleteGroup: () => Promise<boolean>;
|
|
19
|
+
deleteMember: (userId: string) => Promise<boolean>;
|
|
20
|
+
removeMembers: (userIds: string[]) => Promise<boolean>;
|
|
21
|
+
isDeletingGroup: boolean;
|
|
22
|
+
isLeaving: boolean;
|
|
23
|
+
isLoadingMembers: boolean;
|
|
24
|
+
isLoadingMoreMembers: boolean;
|
|
25
|
+
isRenaming: boolean;
|
|
26
|
+
isUpdatingAvatar: boolean;
|
|
27
|
+
isOwner: boolean;
|
|
28
|
+
leave: (nextOwnerId?: string | null) => Promise<boolean>;
|
|
29
|
+
loadMoreMembers: () => Promise<void>;
|
|
30
|
+
memberCountLabel: string;
|
|
31
|
+
memberUserIds: Set<string>;
|
|
32
|
+
members: ConversationMember[];
|
|
33
|
+
membersError: string;
|
|
34
|
+
membersSearch: string;
|
|
35
|
+
nextCursor: string | null;
|
|
36
|
+
otherMembers: ConversationMember[];
|
|
37
|
+
renameConversation: (title: string) => Promise<boolean>;
|
|
38
|
+
searchMembers: (search: string) => Promise<void>;
|
|
39
|
+
updateGroupAvatarFile: (file: File) => Promise<boolean>;
|
|
40
|
+
};
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Whether the full-conversation SearchPanel is open — the header's search button opens
|
|
2
|
+
* it directly (no separate inline header search box to manage a draft for). */
|
|
3
|
+
export declare function useSearchPanel(): {
|
|
4
|
+
isPanelOpen: boolean;
|
|
5
|
+
openPanel: () => void;
|
|
6
|
+
closePanel: () => void;
|
|
7
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ChatMessage, Conversation } from '../../utils/chat';
|
|
2
|
+
export interface ConversationSettingHandle {
|
|
3
|
+
toggleSettings: () => void;
|
|
4
|
+
openSearch: () => void;
|
|
5
|
+
openRename: () => void;
|
|
6
|
+
openMembers: () => void;
|
|
7
|
+
}
|
|
8
|
+
interface ConversationSettingProps {
|
|
9
|
+
conversationId: string | undefined;
|
|
10
|
+
conversation: Conversation | null;
|
|
11
|
+
currentUserId: string | null;
|
|
12
|
+
onConversationUpdated: (update: Partial<Conversation>) => void;
|
|
13
|
+
onDeleteSuccess: () => void;
|
|
14
|
+
onLeaveSuccess: () => void;
|
|
15
|
+
onStartChat: (userId: string) => void;
|
|
16
|
+
onForwardMessage: (message: ChatMessage) => void;
|
|
17
|
+
onOpenUserProfile: (userId: string) => void;
|
|
18
|
+
onSelectSearchMessage: (messageId: string) => Promise<boolean>;
|
|
19
|
+
/** Scrolls the timeline to a message chosen from the documents/media lists. The panel
|
|
20
|
+
* stays open on purpose - jumping is a navigation aid used while browsing the list, so
|
|
21
|
+
* closing it would throw the user out of the list they were working through. Required
|
|
22
|
+
* rather than optional so the jump buttons cannot silently disappear again if this prop
|
|
23
|
+
* is ever dropped while moving these panels around. */
|
|
24
|
+
onJumpToMessage: (message: ChatMessage) => void;
|
|
25
|
+
/** Notifies the page whenever the settings panel or the search panel open/close — the
|
|
26
|
+
* page needs `isSettingsOpen` specifically (the header's settings-toggle button shows
|
|
27
|
+
* its own active state from it) and the combination of both for its "has-side-panel"
|
|
28
|
+
* layout class. The panels themselves stay owned here. */
|
|
29
|
+
onOpenChange: (state: {
|
|
30
|
+
isSettingsOpen: boolean;
|
|
31
|
+
isSearchOpen: boolean;
|
|
32
|
+
}) => void;
|
|
33
|
+
}
|
|
34
|
+
/** Everything under the "Setting" umbrella for the currently open conversation: the
|
|
35
|
+
* search panel, the settings/info panel, the member-list modal, and the rename dialog.
|
|
36
|
+
* Owns their open/closed state itself — the header (a sibling under `conversation/`)
|
|
37
|
+
* only reaches in via the imperative handle to trigger them. */
|
|
38
|
+
export declare const ConversationSetting: import('react').ForwardRefExoticComponent<ConversationSettingProps & import('react').RefAttributes<ConversationSettingHandle>>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface AddMemberModalProps {
|
|
2
|
+
currentUserId: string | null;
|
|
3
|
+
/** Users already in the conversation (plus self) — hidden from the pickable list. */
|
|
4
|
+
memberUserIds: Set<string>;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
onConfirm: (userIds: string[]) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/** "Thêm thành viên" — branch/department filters + search + checkbox multi-select grouped
|
|
9
|
+
* alphabetically, each row showing the avatar, employee code, and job title. */
|
|
10
|
+
export declare function AddMemberModal({ currentUserId, memberUserIds, onClose, onConfirm, }: AddMemberModalProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ConversationMember } from '../../../utils/chat';
|
|
2
|
+
interface GroupMembersModalProps {
|
|
3
|
+
members: ConversationMember[] | undefined;
|
|
4
|
+
memberCount: number;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
/** Opens the account-info modal for a member. */
|
|
7
|
+
onOpenProfile?: (userId: string) => void;
|
|
8
|
+
/** Who is looking — they never get a tick next to their own row. */
|
|
9
|
+
currentUserId?: string | null;
|
|
10
|
+
/** Whether this viewer may remove members at all (group owner, group not verified). */
|
|
11
|
+
canRemove?: boolean;
|
|
12
|
+
isRemoving?: boolean;
|
|
13
|
+
/** Removes the whole tick-selection in one request, so the group gets a single "đã xóa"
|
|
14
|
+
* notice instead of one per person. */
|
|
15
|
+
onDeleteMembers?: (userIds: string[]) => Promise<boolean> | void;
|
|
16
|
+
}
|
|
17
|
+
/** Read-only member list opened from the group header's member count. Reads straight from
|
|
18
|
+
* the conversation's own `members` (kept live in the shared conversationsStore) instead of
|
|
19
|
+
* its own fetch — no separate loading state, and no staleness while it's open. */
|
|
20
|
+
export declare function GroupMembersModal({ members, memberCount, onClose, onOpenProfile, currentUserId, canRemove, isRemoving, onDeleteMembers, }: GroupMembersModalProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Conversation } from '../../../../utils/chat';
|
|
2
|
+
interface UseRenameGroupDialogOptions {
|
|
3
|
+
conversationId: string | undefined;
|
|
4
|
+
onRenamed: (updated: Partial<Conversation>) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Backs the chat-header pencil's "Đổi tên nhóm" dialog: open/saving state plus the
|
|
7
|
+
* rename call itself. */
|
|
8
|
+
export declare function useRenameGroupDialog({ conversationId, onRenamed }: UseRenameGroupDialogOptions): {
|
|
9
|
+
isOpen: boolean;
|
|
10
|
+
open: () => void;
|
|
11
|
+
close: () => void;
|
|
12
|
+
isSaving: boolean;
|
|
13
|
+
submit: (title: string) => Promise<boolean>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface MemberSelectionFooterProps {
|
|
2
|
+
selectedCount: number;
|
|
3
|
+
selectableCount: number;
|
|
4
|
+
isAllSelected: boolean;
|
|
5
|
+
isBusy: boolean;
|
|
6
|
+
onToggleAll: () => void;
|
|
7
|
+
onDelete: () => void;
|
|
8
|
+
}
|
|
9
|
+
/** "Chọn tất cả" + selected count + the destructive action, shared by both member lists so the
|
|
10
|
+
* bulk-remove bar looks and behaves the same wherever it appears. */
|
|
11
|
+
export declare function MemberSelectionFooter({ selectedCount, selectableCount, isAllSelected, isBusy, onToggleAll, onDelete, }: MemberSelectionFooterProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ConversationMember } from '../../../utils/chat';
|
|
2
|
+
interface MembersListModalProps {
|
|
3
|
+
members: ConversationMember[];
|
|
4
|
+
memberCountLabel: string;
|
|
5
|
+
currentUserId: string | null;
|
|
6
|
+
isOwner: boolean;
|
|
7
|
+
isLoadingMembers: boolean;
|
|
8
|
+
membersError: string;
|
|
9
|
+
deletingUserId: string | null;
|
|
10
|
+
nextCursor: string | null;
|
|
11
|
+
isLoadingMoreMembers: boolean;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
onOpenAddModal: () => void;
|
|
14
|
+
onSearch: (search: string) => Promise<void>;
|
|
15
|
+
onDeleteMember: (userId: string) => void;
|
|
16
|
+
/** Removes the whole tick-selection in one request, so the group gets one "đã xóa" notice
|
|
17
|
+
* instead of one per person. */
|
|
18
|
+
onDeleteMembers: (userIds: string[]) => Promise<boolean> | void;
|
|
19
|
+
onLoadMore: () => void;
|
|
20
|
+
/** Opens the account-info modal for a member. */
|
|
21
|
+
onOpenProfile: (userId: string) => void;
|
|
22
|
+
/** True when this is a verified group and the caller lacks hasUpdateGroupVerified —
|
|
23
|
+
* hides (not just disables) add-member and remove-member, the two actions that
|
|
24
|
+
* permission covers. */
|
|
25
|
+
updateLocked?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** "Thành viên" — quick-add row, member list with role subtitle + remove, load-more. */
|
|
28
|
+
export declare function MembersListModal({ members, memberCountLabel, currentUserId, isOwner, isLoadingMembers, membersError, deletingUserId, nextCursor, isLoadingMoreMembers, onClose, onOpenAddModal, onSearch, onDeleteMember, onDeleteMembers, onLoadMore, onOpenProfile, updateLocked, }: MembersListModalProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ChatUser } from '../../../utils/chat';
|
|
3
|
+
interface SettingsModalProps {
|
|
4
|
+
title: string;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
/** Widens the dialog for dense user lists (add-member / members list). */
|
|
8
|
+
medium?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** Shared dialog shell (backdrop + header + close button) for every settings modal.
|
|
11
|
+
* Portals to document.body — without this, a modal opened from inside another modal
|
|
12
|
+
* (e.g. the "Đã chọn" review opened from within the wide create-group modal) would
|
|
13
|
+
* stay a DOM descendant of it, and that ancestor's descendant CSS rules (its 2-column
|
|
14
|
+
* grid, width caps, etc.) would leak in and mangle this modal's own layout.
|
|
15
|
+
* The portaled tree is wrapped in its own `.med-chat-root` because `document.body` is
|
|
16
|
+
* outside the module's scoped root — without it, every `.med-chat-root .chat-modal-*`
|
|
17
|
+
* rule (mask, centering, compact user rows) would silently not apply. The `--portal`
|
|
18
|
+
* modifier renders the wrapper as `display: contents`, so it scopes the styles without
|
|
19
|
+
* adding a 100%-height box after `#root` (which would stretch the page and add a Y scroll). */
|
|
20
|
+
export declare function SettingsModal({ title, children, onClose, medium }: SettingsModalProps): import('react').ReactPortal;
|
|
21
|
+
interface UserIdentityProps {
|
|
22
|
+
user: ChatUser;
|
|
23
|
+
subtitle?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Avatar (real photo when available, else initials) + name (+ optional subtitle below,
|
|
26
|
+
* e.g. "Trưởng nhóm" or a job title) shown in every member row. */
|
|
27
|
+
export declare function UserIdentity({ user, subtitle }: UserIdentityProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
interface RenameGroupDialogProps {
|
|
29
|
+
initialTitle: string;
|
|
30
|
+
isSaving: boolean;
|
|
31
|
+
onClose: () => void;
|
|
32
|
+
onRename: (title: string) => Promise<boolean>;
|
|
33
|
+
}
|
|
34
|
+
/** Shared "Đổi tên nhóm" dialog used from both the settings panel and the chat-header pencil. */
|
|
35
|
+
export declare function RenameGroupDialog({ initialTitle, isSaving, onClose, onRename }: RenameGroupDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface UseMemberSelectionOptions {
|
|
2
|
+
/** Every member the current view could actually remove — the owner and the current user are
|
|
3
|
+
* already excluded by the caller. */
|
|
4
|
+
selectableUserIds: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Tick-selection shared by the two member lists (the settings panel's list and the read-only
|
|
8
|
+
* one opened from the group header), so "Chọn tất cả" means the same thing in both.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useMemberSelection({ selectableUserIds }: UseMemberSelectionOptions): {
|
|
11
|
+
selectedUserIds: string[];
|
|
12
|
+
isAllSelected: boolean;
|
|
13
|
+
isSelected: (userId: string) => boolean;
|
|
14
|
+
toggle: (userId: string) => void;
|
|
15
|
+
toggleAll: () => void;
|
|
16
|
+
clear: () => void;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ConversationMember } from '../../utils/chat';
|
|
2
|
+
interface SearchPanelProps {
|
|
3
|
+
conversationId: string | undefined;
|
|
4
|
+
members: ConversationMember[] | undefined;
|
|
5
|
+
initialQuery?: string;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onSelectMessage: (messageId: string) => Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
/** Slide-over panel searching a conversation's messages and documents, with "Người gửi"/
|
|
10
|
+
* "Ngày gửi" filters and matched-term highlighting (from the backend's `ts_headline`
|
|
11
|
+
* snippet) in each result row. */
|
|
12
|
+
export declare function SearchPanel({ conversationId, members, initialQuery, onClose, onSelectMessage, }: SearchPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { VirtuosoHandle } from 'react-virtuoso';
|
|
2
|
+
import { RefObject } from 'react';
|
|
3
|
+
import { MessageRemovedPayload } from '@medipha/chat-core';
|
|
4
|
+
import { ChatMessage, ChatUser, ConversationMember } from '../../../utils/chat';
|
|
5
|
+
import { PendingAttachment } from '../../../features/composer/pending-attachment';
|
|
6
|
+
interface MessageWindowForDetail {
|
|
7
|
+
messages: ChatMessage[];
|
|
8
|
+
firstItemIndex: number;
|
|
9
|
+
timelineRevision: number;
|
|
10
|
+
focusedMessageId: string | null;
|
|
11
|
+
loadOlder: () => void;
|
|
12
|
+
loadNewer: () => void;
|
|
13
|
+
updateAtBottom: (isAtBottom: boolean) => void;
|
|
14
|
+
isLoadingOlder: boolean;
|
|
15
|
+
isLoadingNewer: boolean;
|
|
16
|
+
hasUnseenMessages: boolean;
|
|
17
|
+
isAtBottom: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface ReplyTargetForDetail {
|
|
20
|
+
replyTarget: ChatMessage | null;
|
|
21
|
+
startReply: (message: ChatMessage) => void;
|
|
22
|
+
clearReply: () => void;
|
|
23
|
+
}
|
|
24
|
+
export interface ConversationDetailHandle {
|
|
25
|
+
/** Closes the per-message "..." menu — used by the parent's scroll handler (scrolling
|
|
26
|
+
* away from a message shouldn't leave its menu floating over new content). */
|
|
27
|
+
closeMessageMenu: () => void;
|
|
28
|
+
}
|
|
29
|
+
interface ConversationDetailProps {
|
|
30
|
+
conversationId: string | undefined;
|
|
31
|
+
timelineRef: RefObject<HTMLDivElement>;
|
|
32
|
+
isLoading: boolean;
|
|
33
|
+
chatError: string;
|
|
34
|
+
isTimelineReady: boolean;
|
|
35
|
+
isFollowingLatest: boolean;
|
|
36
|
+
messageWindow: MessageWindowForDetail;
|
|
37
|
+
/** Rejects late realtime payloads (pin, etc.) for a message removed earlier this session. */
|
|
38
|
+
isRemovedMessageId: (messageId: string) => boolean;
|
|
39
|
+
virtuosoRef: RefObject<VirtuosoHandle>;
|
|
40
|
+
setScrollerRef: (element: unknown) => void;
|
|
41
|
+
handleTimelineScrolling: (scrolling: boolean) => void;
|
|
42
|
+
handleVisibleRangeChanged: (range: {
|
|
43
|
+
startIndex: number;
|
|
44
|
+
endIndex: number;
|
|
45
|
+
}) => void;
|
|
46
|
+
visibleDayLabel: string | null;
|
|
47
|
+
isNearBottomOfList: boolean;
|
|
48
|
+
onCatchUp: () => void;
|
|
49
|
+
members: ConversationMember[] | undefined;
|
|
50
|
+
isGroup: boolean;
|
|
51
|
+
/** Active members + self — only used to size the "seen by" modal's member picker. */
|
|
52
|
+
groupMemberCount: number;
|
|
53
|
+
currentUserId: string | null;
|
|
54
|
+
authUser: ChatUser | null;
|
|
55
|
+
composerError: string;
|
|
56
|
+
pendingAttachments: PendingAttachment[];
|
|
57
|
+
onRemovePendingAttachment: (index: number) => void;
|
|
58
|
+
typingNames: string[];
|
|
59
|
+
canModerateMessages: boolean;
|
|
60
|
+
canManagePins: boolean;
|
|
61
|
+
dayDividerKeys: Set<string>;
|
|
62
|
+
replyTargetState: ReplyTargetForDetail;
|
|
63
|
+
onForward: (message: ChatMessage) => void;
|
|
64
|
+
onJumpToReply: (replyMessageId: string) => void;
|
|
65
|
+
onOpenMentionCard: (userId: string) => void;
|
|
66
|
+
onOpenUserProfile: (userId: string) => void;
|
|
67
|
+
onOpenImageLightbox: (message: ChatMessage, urls: string[], index: number) => void;
|
|
68
|
+
onRetry: (message: ChatMessage) => void;
|
|
69
|
+
/** Failed sends never reached the server (no `id`), so removing one is a local-only drop. */
|
|
70
|
+
onDeleteFailed: (message: ChatMessage) => void;
|
|
71
|
+
/** Read synchronously (not via React state) so an image-load event mid-render doesn't
|
|
72
|
+
* scroll on stale data — see the hook's own note on why this stays a ref. */
|
|
73
|
+
stickToLatestRef: RefObject<boolean>;
|
|
74
|
+
readIsFollowingLatest: () => boolean;
|
|
75
|
+
scrollToLatest: (behavior?: 'auto' | 'smooth') => void;
|
|
76
|
+
/** Backs the pinned-messages bar's "jump to message" action. */
|
|
77
|
+
loadAround: (messageId: string) => Promise<boolean> | boolean;
|
|
78
|
+
/** A message was removed (this user's own confirm-flow, or a realtime event) — the
|
|
79
|
+
* parent applies its own share of the fallout (messageWindow tombstone, reply target,
|
|
80
|
+
* the page-level forward picker, the image lightbox); this view applies the rest
|
|
81
|
+
* (pin, reaction, menu, details) itself. */
|
|
82
|
+
onMessageRemoved: (removal: MessageRemovedPayload) => void;
|
|
83
|
+
}
|
|
84
|
+
/** Everything below the header: the pinned-messages bar, the scrollable message body
|
|
85
|
+
* (Virtuoso list, loading/empty states, day pill, catch-up buttons), the per-row
|
|
86
|
+
* MessageBubble wiring, and the transient strips right above the composer — reply
|
|
87
|
+
* banner, staged attachment previews, typing indicator. Owns every overlay that's
|
|
88
|
+
* exclusively its own concern (pin, reaction picker/modal, message menu, message
|
|
89
|
+
* details, removal) — only genuinely cross-cutting state (message window, reply
|
|
90
|
+
* target, typing...) still comes from `conversation/index.tsx`. */
|
|
91
|
+
export declare const ConversationDetail: import('react').ForwardRefExoticComponent<ConversationDetailProps & import('react').RefAttributes<ConversationDetailHandle>>;
|
|
92
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { PendingAttachment } from '../../../features/composer/pending-attachment';
|
|
3
|
+
import { ChatMessage, ChatUser } from '../../../utils/chat';
|
|
4
|
+
interface PendingAttachmentsForFooter {
|
|
5
|
+
pendingAttachments: PendingAttachment[];
|
|
6
|
+
addFiles: (files: File[], options?: {
|
|
7
|
+
forceDocument?: boolean;
|
|
8
|
+
}) => boolean;
|
|
9
|
+
clear: () => void;
|
|
10
|
+
}
|
|
11
|
+
interface ReplyTargetForFooter {
|
|
12
|
+
replyTarget: ChatMessage | null;
|
|
13
|
+
clearReply: () => void;
|
|
14
|
+
}
|
|
15
|
+
interface ConversationFooterProps {
|
|
16
|
+
conversationId: string | undefined;
|
|
17
|
+
currentUserId: string | null;
|
|
18
|
+
conversationTitle: string;
|
|
19
|
+
mentionMembers: ChatUser[];
|
|
20
|
+
canMentionAll: boolean;
|
|
21
|
+
isGroup: boolean;
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
pendingAttachmentsState: PendingAttachmentsForFooter;
|
|
24
|
+
replyTargetState: ReplyTargetForFooter;
|
|
25
|
+
emitOutgoingMessage: (message: ChatMessage) => void;
|
|
26
|
+
markMessageFailed: (message: ChatMessage, failureStage: 'upload' | 'send') => void;
|
|
27
|
+
mergeOutgoingMessage: (message: ChatMessage) => void;
|
|
28
|
+
stickToLatest: () => void;
|
|
29
|
+
onComposerError: (message: string) => void;
|
|
30
|
+
onAttach: () => void;
|
|
31
|
+
onAttachImages: () => void;
|
|
32
|
+
onTypingStart: () => void;
|
|
33
|
+
onTypingStop: () => void;
|
|
34
|
+
uploadInputRef: RefObject<HTMLInputElement>;
|
|
35
|
+
imageUploadInputRef: RefObject<HTMLInputElement>;
|
|
36
|
+
acceptAttribute: string;
|
|
37
|
+
}
|
|
38
|
+
/** The message composer itself — toolbar + input — plus its two hidden file inputs. Owns
|
|
39
|
+
* turning a submitted draft (text and/or staged attachments) into outgoing messages,
|
|
40
|
+
* including uploading any staged files before they're sent. */
|
|
41
|
+
export declare function ConversationFooter({ conversationId, currentUserId, conversationTitle, mentionMembers, canMentionAll, isGroup, disabled, pendingAttachmentsState, replyTargetState, emitOutgoingMessage, markMessageFailed, mergeOutgoingMessage, stickToLatest, onComposerError, onAttach, onAttachImages, onTypingStart, onTypingStop, uploadInputRef, imageUploadInputRef, acceptAttribute, }: ConversationFooterProps): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ConversationMember } from '../../../utils/chat';
|
|
2
|
+
interface ConversationHeaderProps {
|
|
3
|
+
title: string;
|
|
4
|
+
avatarUrl?: string | null;
|
|
5
|
+
isGroup: boolean;
|
|
6
|
+
isVerified?: boolean;
|
|
7
|
+
groupMemberCount: number;
|
|
8
|
+
members?: ConversationMember[];
|
|
9
|
+
currentUserId?: string | null;
|
|
10
|
+
isOtherMemberOnline: boolean | undefined;
|
|
11
|
+
/** Opens the full SearchPanel directly. */
|
|
12
|
+
onOpenSearch: () => void;
|
|
13
|
+
onOpenMessageList: () => void;
|
|
14
|
+
isSettingsOpen: boolean;
|
|
15
|
+
onToggleSettings: () => void;
|
|
16
|
+
/** Group only: opens the member-list modal from the header member count. */
|
|
17
|
+
onOpenMembers?: () => void;
|
|
18
|
+
/** Clicking the avatar opens the partner's account info (direct chats) or a fullscreen
|
|
19
|
+
* preview of the group photo (groups). */
|
|
20
|
+
onOpenAvatarProfile?: () => void;
|
|
21
|
+
/** Group owner only: hovering the title reveals a rename button. */
|
|
22
|
+
canEditTitle?: boolean;
|
|
23
|
+
onEditTitle?: () => void;
|
|
24
|
+
}
|
|
25
|
+
/** Conversation title/status row plus the collapsible in-header search and toggle buttons. */
|
|
26
|
+
export declare function ConversationHeader({ title, avatarUrl, isGroup, isVerified, groupMemberCount, members, currentUserId, isOtherMemberOnline, onOpenSearch, onOpenMessageList, isSettingsOpen, onToggleSettings, onOpenMembers, canEditTitle, onEditTitle, onOpenAvatarProfile, }: ConversationHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ChatUser } from '../../../utils/chat';
|
|
2
|
+
/**
|
|
3
|
+
* Owns the current user's membership info for a GROUP conversation — the active member
|
|
4
|
+
* list used for @mention autocomplete, and the current user's own role/status, used
|
|
5
|
+
* across permission checks (pin management, moderation, title editing). A no-op for
|
|
6
|
+
* DIRECT conversations, which have no membership roles to resolve.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useCurrentMembership(conversationId: string | undefined, conversationType: string, currentUserId: string | null, onError: (message: string) => void): {
|
|
9
|
+
mentionMembers: ChatUser[];
|
|
10
|
+
currentMemberRole: string;
|
|
11
|
+
currentMemberStatus: string;
|
|
12
|
+
reload: () => Promise<void>;
|
|
13
|
+
reset: () => void;
|
|
14
|
+
};
|