@weavy/uikit-react 11.0.0
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/.github/workflows/publish.yml +16 -0
- package/LICENSE.md +21 -0
- package/README.md +110 -0
- package/changelog.md +50 -0
- package/dist/cjs/index.js +39 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types/client/WeavyClient.d.ts +16 -0
- package/dist/cjs/types/components/Attachment.d.ts +13 -0
- package/dist/cjs/types/components/Avatar.d.ts +11 -0
- package/dist/cjs/types/components/Chat.d.ts +4 -0
- package/dist/cjs/types/components/Conversation.d.ts +4 -0
- package/dist/cjs/types/components/ConversationBadge.d.ts +3 -0
- package/dist/cjs/types/components/ConversationForm.d.ts +7 -0
- package/dist/cjs/types/components/ConversationList.d.ts +3 -0
- package/dist/cjs/types/components/ConversationListItem.d.ts +4 -0
- package/dist/cjs/types/components/File.d.ts +9 -0
- package/dist/cjs/types/components/FileBrowser.d.ts +6 -0
- package/dist/cjs/types/components/Image.d.ts +16 -0
- package/dist/cjs/types/components/Meeting.d.ts +8 -0
- package/dist/cjs/types/components/MeetingCard.d.ts +6 -0
- package/dist/cjs/types/components/Meetings.d.ts +6 -0
- package/dist/cjs/types/components/Message.d.ts +4 -0
- package/dist/cjs/types/components/Messages.d.ts +9 -0
- package/dist/cjs/types/components/Messenger.d.ts +4 -0
- package/dist/cjs/types/components/NewConversation.d.ts +3 -0
- package/dist/cjs/types/components/Presence.d.ts +7 -0
- package/dist/cjs/types/components/Reactions.d.ts +13 -0
- package/dist/cjs/types/components/SearchUsers.d.ts +7 -0
- package/dist/cjs/types/components/SeenBy.d.ts +9 -0
- package/dist/cjs/types/components/Typing.d.ts +8 -0
- package/dist/cjs/types/contexts/MessengerContext.d.ts +8 -0
- package/dist/cjs/types/contexts/PreviewContext.d.ts +7 -0
- package/dist/cjs/types/contexts/UserContext.d.ts +8 -0
- package/dist/cjs/types/contexts/WeavyContext.d.ts +10 -0
- package/dist/cjs/types/hooks/useBadge.d.ts +1 -0
- package/dist/cjs/types/hooks/useChat.d.ts +1 -0
- package/dist/cjs/types/hooks/useConversation.d.ts +1 -0
- package/dist/cjs/types/hooks/useConversations.d.ts +1 -0
- package/dist/cjs/types/hooks/useDebounce.d.ts +2 -0
- package/dist/cjs/types/hooks/useEvents.d.ts +6 -0
- package/dist/cjs/types/hooks/useFileUploader.d.ts +1 -0
- package/dist/cjs/types/hooks/useMembers.d.ts +1 -0
- package/dist/cjs/types/hooks/useMessages.d.ts +1 -0
- package/dist/cjs/types/hooks/useMutateChat.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateConversation.d.ts +3 -0
- package/dist/cjs/types/hooks/useMutateConversationName.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateDeleteReaction.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateExternalBlobs.d.ts +3 -0
- package/dist/cjs/types/hooks/useMutateMeeting.d.ts +3 -0
- package/dist/cjs/types/hooks/useMutateMembers.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateMessage.d.ts +9 -0
- package/dist/cjs/types/hooks/useMutatePinned.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateReaction.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateRead.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateRemoveMembers.d.ts +4 -0
- package/dist/cjs/types/hooks/useMutateTyping.d.ts +3 -0
- package/dist/cjs/types/hooks/usePresence.d.ts +1 -0
- package/dist/cjs/types/hooks/usePreview.d.ts +4 -0
- package/dist/cjs/types/hooks/useReactions.d.ts +3 -0
- package/dist/cjs/types/hooks/useSearchUsers.d.ts +1 -0
- package/dist/cjs/types/hooks/useThrottle.d.ts +2 -0
- package/dist/cjs/types/hooks/useUser.d.ts +1 -0
- package/dist/cjs/types/index.d.ts +15 -0
- package/dist/cjs/types/types/Chat.d.ts +3 -0
- package/dist/cjs/types/types/Conversation.d.ts +4 -0
- package/dist/cjs/types/types/ConversationListItem.d.ts +4 -0
- package/dist/cjs/types/types/Message.d.ts +15 -0
- package/dist/cjs/types/types/Messenger.d.ts +3 -0
- package/dist/cjs/types/types/types.d.ts +150 -0
- package/dist/cjs/types/ui/Button.d.ts +4 -0
- package/dist/cjs/types/ui/Dropdown.d.ts +19 -0
- package/dist/cjs/types/ui/Icon.d.ts +10 -0
- package/dist/cjs/types/ui/Overlay.d.ts +12 -0
- package/dist/cjs/types/utils/fileUtilities.d.ts +5 -0
- package/dist/cjs/types/utils/styles.d.ts +17 -0
- package/dist/esm/index.js +39 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types/client/WeavyClient.d.ts +16 -0
- package/dist/esm/types/components/Attachment.d.ts +13 -0
- package/dist/esm/types/components/Avatar.d.ts +11 -0
- package/dist/esm/types/components/Chat.d.ts +4 -0
- package/dist/esm/types/components/Conversation.d.ts +4 -0
- package/dist/esm/types/components/ConversationBadge.d.ts +3 -0
- package/dist/esm/types/components/ConversationForm.d.ts +7 -0
- package/dist/esm/types/components/ConversationList.d.ts +3 -0
- package/dist/esm/types/components/ConversationListItem.d.ts +4 -0
- package/dist/esm/types/components/File.d.ts +9 -0
- package/dist/esm/types/components/FileBrowser.d.ts +6 -0
- package/dist/esm/types/components/Image.d.ts +16 -0
- package/dist/esm/types/components/Meeting.d.ts +8 -0
- package/dist/esm/types/components/MeetingCard.d.ts +6 -0
- package/dist/esm/types/components/Meetings.d.ts +6 -0
- package/dist/esm/types/components/Message.d.ts +4 -0
- package/dist/esm/types/components/Messages.d.ts +9 -0
- package/dist/esm/types/components/Messenger.d.ts +4 -0
- package/dist/esm/types/components/NewConversation.d.ts +3 -0
- package/dist/esm/types/components/Presence.d.ts +7 -0
- package/dist/esm/types/components/Reactions.d.ts +13 -0
- package/dist/esm/types/components/SearchUsers.d.ts +7 -0
- package/dist/esm/types/components/SeenBy.d.ts +9 -0
- package/dist/esm/types/components/Typing.d.ts +8 -0
- package/dist/esm/types/contexts/MessengerContext.d.ts +8 -0
- package/dist/esm/types/contexts/PreviewContext.d.ts +7 -0
- package/dist/esm/types/contexts/UserContext.d.ts +8 -0
- package/dist/esm/types/contexts/WeavyContext.d.ts +10 -0
- package/dist/esm/types/hooks/useBadge.d.ts +1 -0
- package/dist/esm/types/hooks/useChat.d.ts +1 -0
- package/dist/esm/types/hooks/useConversation.d.ts +1 -0
- package/dist/esm/types/hooks/useConversations.d.ts +1 -0
- package/dist/esm/types/hooks/useDebounce.d.ts +2 -0
- package/dist/esm/types/hooks/useEvents.d.ts +6 -0
- package/dist/esm/types/hooks/useFileUploader.d.ts +1 -0
- package/dist/esm/types/hooks/useMembers.d.ts +1 -0
- package/dist/esm/types/hooks/useMessages.d.ts +1 -0
- package/dist/esm/types/hooks/useMutateChat.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateConversation.d.ts +3 -0
- package/dist/esm/types/hooks/useMutateConversationName.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateDeleteReaction.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateExternalBlobs.d.ts +3 -0
- package/dist/esm/types/hooks/useMutateMeeting.d.ts +3 -0
- package/dist/esm/types/hooks/useMutateMembers.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateMessage.d.ts +9 -0
- package/dist/esm/types/hooks/useMutatePinned.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateReaction.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateRead.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateRemoveMembers.d.ts +4 -0
- package/dist/esm/types/hooks/useMutateTyping.d.ts +3 -0
- package/dist/esm/types/hooks/usePresence.d.ts +1 -0
- package/dist/esm/types/hooks/usePreview.d.ts +4 -0
- package/dist/esm/types/hooks/useReactions.d.ts +3 -0
- package/dist/esm/types/hooks/useSearchUsers.d.ts +1 -0
- package/dist/esm/types/hooks/useThrottle.d.ts +2 -0
- package/dist/esm/types/hooks/useUser.d.ts +1 -0
- package/dist/esm/types/index.d.ts +15 -0
- package/dist/esm/types/types/Chat.d.ts +3 -0
- package/dist/esm/types/types/Conversation.d.ts +4 -0
- package/dist/esm/types/types/ConversationListItem.d.ts +4 -0
- package/dist/esm/types/types/Message.d.ts +15 -0
- package/dist/esm/types/types/Messenger.d.ts +3 -0
- package/dist/esm/types/types/types.d.ts +150 -0
- package/dist/esm/types/ui/Button.d.ts +4 -0
- package/dist/esm/types/ui/Dropdown.d.ts +19 -0
- package/dist/esm/types/ui/Icon.d.ts +10 -0
- package/dist/esm/types/ui/Overlay.d.ts +12 -0
- package/dist/esm/types/utils/fileUtilities.d.ts +5 -0
- package/dist/esm/types/utils/styles.d.ts +17 -0
- package/dist/index.d.ts +98 -0
- package/package.json +47 -0
- package/rollup.config.js +41 -0
- package/src/client/WeavyClient.ts +95 -0
- package/src/components/Attachment.tsx +33 -0
- package/src/components/Avatar.tsx +26 -0
- package/src/components/Chat.tsx +68 -0
- package/src/components/Conversation.tsx +220 -0
- package/src/components/ConversationBadge.tsx +44 -0
- package/src/components/ConversationForm.tsx +217 -0
- package/src/components/ConversationList.tsx +61 -0
- package/src/components/ConversationListItem.tsx +155 -0
- package/src/components/File.tsx +21 -0
- package/src/components/FileBrowser.tsx +86 -0
- package/src/components/Image.tsx +66 -0
- package/src/components/Meeting.tsx +21 -0
- package/src/components/MeetingCard.tsx +31 -0
- package/src/components/Meetings.tsx +58 -0
- package/src/components/Message.tsx +90 -0
- package/src/components/Messages.tsx +271 -0
- package/src/components/Messenger.tsx +34 -0
- package/src/components/NewConversation.tsx +50 -0
- package/src/components/Presence.tsx +15 -0
- package/src/components/Reactions.tsx +95 -0
- package/src/components/SearchUsers.tsx +90 -0
- package/src/components/SeenBy.tsx +26 -0
- package/src/components/Typing.tsx +131 -0
- package/src/contexts/MessengerContext.tsx +44 -0
- package/src/contexts/PreviewContext.tsx +105 -0
- package/src/contexts/UserContext.tsx +31 -0
- package/src/contexts/WeavyContext.tsx +66 -0
- package/src/hooks/useBadge.ts +32 -0
- package/src/hooks/useChat.ts +32 -0
- package/src/hooks/useConversation.ts +28 -0
- package/src/hooks/useConversations.ts +27 -0
- package/src/hooks/useDebounce.ts +22 -0
- package/src/hooks/useEvents.ts +43 -0
- package/src/hooks/useFileUploader.ts +35 -0
- package/src/hooks/useMembers.ts +27 -0
- package/src/hooks/useMessages.ts +42 -0
- package/src/hooks/useMessenger.ts +51 -0
- package/src/hooks/useMutateChat.ts +44 -0
- package/src/hooks/useMutateConversation.ts +40 -0
- package/src/hooks/useMutateConversationName.ts +41 -0
- package/src/hooks/useMutateDeleteReaction.ts +38 -0
- package/src/hooks/useMutateExternalBlobs.ts +39 -0
- package/src/hooks/useMutateMeeting.ts +39 -0
- package/src/hooks/useMutateMembers.ts +43 -0
- package/src/hooks/useMutateMessage.ts +116 -0
- package/src/hooks/useMutatePinned.ts +40 -0
- package/src/hooks/useMutateReaction.ts +38 -0
- package/src/hooks/useMutateRead.ts +40 -0
- package/src/hooks/useMutateRemoveMembers.ts +43 -0
- package/src/hooks/useMutateTyping.ts +34 -0
- package/src/hooks/usePresence.ts +32 -0
- package/src/hooks/usePreview.ts +21 -0
- package/src/hooks/useReactions.ts +53 -0
- package/src/hooks/useSearchUsers.ts +26 -0
- package/src/hooks/useThrottle.ts +13 -0
- package/src/hooks/useUser.ts +38 -0
- package/src/index.ts +33 -0
- package/src/types/Chat.ts +3 -0
- package/src/types/Conversation.ts +4 -0
- package/src/types/ConversationListItem.ts +4 -0
- package/src/types/Message.ts +16 -0
- package/src/types/Messenger.ts +3 -0
- package/src/types/emoji-toolkit.d.ts +1 -0
- package/src/types/types.ts +175 -0
- package/src/ui/Button.tsx +32 -0
- package/src/ui/Dropdown.tsx +58 -0
- package/src/ui/Icon.tsx +79 -0
- package/src/ui/Overlay.tsx +41 -0
- package/src/utils/fileUtilities.ts +230 -0
- package/src/utils/infiniteScroll.js +175 -0
- package/src/utils/scrollToBottom.js +75 -0
- package/src/utils/styles.ts +42 -0
- package/tsconfig.json +108 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Styles } from 'react-modal';
|
|
3
|
+
declare type OverlayProps = {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
isOpen: boolean;
|
|
7
|
+
style?: Styles;
|
|
8
|
+
};
|
|
9
|
+
declare const UIOverlay: {
|
|
10
|
+
UI: ({ children, className, isOpen, style }: OverlayProps) => JSX.Element;
|
|
11
|
+
};
|
|
12
|
+
export default UIOverlay;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets the prefix for CSS classes on the HTML element for usage in javascript.
|
|
3
|
+
* @param {string} prefix
|
|
4
|
+
*/
|
|
5
|
+
export declare function setPrefix(prefix: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Prefixes one or more classnames (with or without dot) using the themePrefix
|
|
8
|
+
* @param {...string} strs
|
|
9
|
+
* @returns string[]
|
|
10
|
+
*/
|
|
11
|
+
export declare function prefixes(...strs: string[]): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Prefixes one classname (with or without dot) using the themePrefix
|
|
14
|
+
* @param {string} str
|
|
15
|
+
* @returns string
|
|
16
|
+
*/
|
|
17
|
+
export declare function prefix(str: string): string;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import * as _microsoft_signalr from '@microsoft/signalr';
|
|
3
|
+
import React, { FC } from 'react';
|
|
4
|
+
import { Styles } from 'react-modal';
|
|
5
|
+
|
|
6
|
+
declare class WeavyClient {
|
|
7
|
+
uri: string;
|
|
8
|
+
tokenFactory: () => string | Promise<string>;
|
|
9
|
+
connection: _microsoft_signalr.HubConnection;
|
|
10
|
+
groups: string[];
|
|
11
|
+
connectionEvents: any[];
|
|
12
|
+
isConnectionStarted: any;
|
|
13
|
+
EVENT_NAMESPACE: string;
|
|
14
|
+
EVENT_CLOSE: string;
|
|
15
|
+
EVENT_RECONNECTING: string;
|
|
16
|
+
EVENT_RECONNECTED: string;
|
|
17
|
+
constructor(options: WeavyClientOptions);
|
|
18
|
+
subscribe(group: string, event: string, callback: any): Promise<void>;
|
|
19
|
+
unsubscribe(group: string, event: string, callback: any): Promise<void>;
|
|
20
|
+
triggerHandler(name: string, ...data: any): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare const WeavyContext: React.Context<WeavyContextProps>;
|
|
24
|
+
declare type Props$2 = {
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
client: WeavyClient;
|
|
27
|
+
options?: WeavyContextOptions;
|
|
28
|
+
};
|
|
29
|
+
declare const WeavyProvider: ({ children, client, options }: Props$2) => JSX.Element;
|
|
30
|
+
|
|
31
|
+
declare const MessengerContext: React.Context<MessengerContextProps>;
|
|
32
|
+
declare type Props$1 = {
|
|
33
|
+
children: React.ReactNode;
|
|
34
|
+
options?: MessengerContextOptions;
|
|
35
|
+
};
|
|
36
|
+
declare const MessengerProvider: ({ children, options }: Props$1) => JSX.Element;
|
|
37
|
+
|
|
38
|
+
declare const Messenger: FC<Messenger>;
|
|
39
|
+
|
|
40
|
+
declare const ConversationBadge: () => JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare const ConversationList: () => JSX.Element;
|
|
43
|
+
|
|
44
|
+
interface ConversationProps {
|
|
45
|
+
id?: number | null;
|
|
46
|
+
showBackButton?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare const _default: React.MemoExoticComponent<({ id, showBackButton }: ConversationProps) => JSX.Element>;
|
|
50
|
+
|
|
51
|
+
interface ChatProps {
|
|
52
|
+
id: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare const Chat: ({ id }: ChatProps) => JSX.Element;
|
|
56
|
+
|
|
57
|
+
declare const UIButton: {
|
|
58
|
+
UI: any;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
declare type DropdownProps = {
|
|
62
|
+
directionX?: "left" | "right";
|
|
63
|
+
directionY?: "up" | "down";
|
|
64
|
+
children: React.ReactNode;
|
|
65
|
+
className?: string;
|
|
66
|
+
props?: React.HTMLAttributes<HTMLSpanElement>;
|
|
67
|
+
};
|
|
68
|
+
declare type ItemProps = {
|
|
69
|
+
children: React.ReactNode;
|
|
70
|
+
className?: string;
|
|
71
|
+
onClick?: (e: any) => void;
|
|
72
|
+
props?: React.HTMLAttributes<HTMLDivElement>;
|
|
73
|
+
};
|
|
74
|
+
declare const UIDropdown: {
|
|
75
|
+
UI: ({ directionX, directionY, children, className, ...props }: DropdownProps) => JSX.Element;
|
|
76
|
+
Item: ({ children, className, onClick, ...props }: ItemProps) => JSX.Element;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
declare type Props = {
|
|
80
|
+
name: string;
|
|
81
|
+
color?: string;
|
|
82
|
+
size?: number;
|
|
83
|
+
};
|
|
84
|
+
declare const UIIcon: {
|
|
85
|
+
UI: ({ name, color, size, ...props }: Props) => JSX.Element;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
declare type OverlayProps = {
|
|
89
|
+
children: React.ReactNode;
|
|
90
|
+
className?: string;
|
|
91
|
+
isOpen: boolean;
|
|
92
|
+
style?: Styles;
|
|
93
|
+
};
|
|
94
|
+
declare const UIOverlay: {
|
|
95
|
+
UI: ({ children, className, isOpen, style }: OverlayProps) => JSX.Element;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export { UIButton as Button, Chat, _default as Conversation, ConversationBadge, ConversationList, UIDropdown as Dropdown, UIIcon as Icon, Messenger, MessengerContext, MessengerProvider, UIOverlay as Overlay, WeavyClient, WeavyContext, WeavyProvider };
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weavy/uikit-react",
|
|
3
|
+
"version": "11.0.0",
|
|
4
|
+
"author": "Weavy",
|
|
5
|
+
"description": "React UI-kit for Weavy",
|
|
6
|
+
"homepage": "https://github.com/weavy/weavy-uikit-react",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"main": "dist/cjs/index.js",
|
|
9
|
+
"module": "dist/esm/index.js",
|
|
10
|
+
"types": "./dist/cjs/types/index.d.ts",
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@rollup/plugin-commonjs": "^22.0.0",
|
|
13
|
+
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
14
|
+
"@rollup/plugin-typescript": "^8.3.1",
|
|
15
|
+
"@types/lodash.debounce": "^4.0.7",
|
|
16
|
+
"@types/lodash.throttle": "^4.1.7",
|
|
17
|
+
"@types/react": "^18.0.8",
|
|
18
|
+
"@types/react-dom": "^18.0.3",
|
|
19
|
+
"@types/react-modal": "^3.13.1",
|
|
20
|
+
"rollup": "^2.72.0",
|
|
21
|
+
"rollup-plugin-delete": "^2.0.0",
|
|
22
|
+
"rollup-plugin-dts": "^4.2.1",
|
|
23
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
24
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
25
|
+
"tslib": "^2.4.0",
|
|
26
|
+
"typescript": "^4.6.4"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": "^18.1.0",
|
|
30
|
+
"react-dom": "^18.1.0"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "rollup -c",
|
|
34
|
+
"watch": "rollup -c --watch"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@mdi/react": "^1.6.0",
|
|
38
|
+
"@microsoft/signalr": "^6.0.3",
|
|
39
|
+
"classnames": "^2.3.1",
|
|
40
|
+
"dayjs": "^1.11.1",
|
|
41
|
+
"emoji-toolkit": "^6.6.0",
|
|
42
|
+
"lodash.debounce": "^4.0.8",
|
|
43
|
+
"lodash.throttle": "^4.1.1",
|
|
44
|
+
"react-modal": "^3.14.4",
|
|
45
|
+
"react-query": "^3.34.16"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import resolve from "@rollup/plugin-node-resolve";
|
|
2
|
+
import commonjs from "@rollup/plugin-commonjs";
|
|
3
|
+
import typescript from "@rollup/plugin-typescript";
|
|
4
|
+
import dts from "rollup-plugin-dts";
|
|
5
|
+
import { terser } from "rollup-plugin-terser";
|
|
6
|
+
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
|
|
7
|
+
import del from 'rollup-plugin-delete';
|
|
8
|
+
|
|
9
|
+
const packageJson = require("./package.json");
|
|
10
|
+
|
|
11
|
+
export default [
|
|
12
|
+
{
|
|
13
|
+
input: "src/index.ts",
|
|
14
|
+
output: [
|
|
15
|
+
{
|
|
16
|
+
file: packageJson.main,
|
|
17
|
+
format: "cjs",
|
|
18
|
+
sourcemap: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
file: packageJson.module,
|
|
22
|
+
format: "esm",
|
|
23
|
+
sourcemap: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
plugins: [
|
|
27
|
+
del({ targets: 'dist/*' }),
|
|
28
|
+
peerDepsExternal(),
|
|
29
|
+
resolve(),
|
|
30
|
+
commonjs(),
|
|
31
|
+
typescript({ tsconfig: "./tsconfig.json" }),
|
|
32
|
+
terser(),
|
|
33
|
+
],
|
|
34
|
+
external: ["react", "react-dom"]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
input: "dist/esm/types/index.d.ts",
|
|
38
|
+
output: [{ file: "dist/index.d.ts", format: "esm" }],
|
|
39
|
+
plugins: [dts()],
|
|
40
|
+
},
|
|
41
|
+
];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
|
|
2
|
+
|
|
3
|
+
export default class WeavyClient {
|
|
4
|
+
uri;
|
|
5
|
+
tokenFactory;
|
|
6
|
+
connection;
|
|
7
|
+
groups: string[];
|
|
8
|
+
connectionEvents: any[];
|
|
9
|
+
isConnectionStarted: any;
|
|
10
|
+
|
|
11
|
+
EVENT_NAMESPACE = ".connection";
|
|
12
|
+
EVENT_CLOSE = "close";
|
|
13
|
+
EVENT_RECONNECTING = "reconnecting";
|
|
14
|
+
EVENT_RECONNECTED = "reconnected";
|
|
15
|
+
|
|
16
|
+
constructor(options: WeavyClientOptions) {
|
|
17
|
+
this.uri = options.uri;
|
|
18
|
+
this.tokenFactory = options.tokenFactory
|
|
19
|
+
this.groups = [];
|
|
20
|
+
this.connectionEvents = [];
|
|
21
|
+
|
|
22
|
+
this.connection = new HubConnectionBuilder()
|
|
23
|
+
.configureLogging(LogLevel.None)
|
|
24
|
+
.withUrl(this.uri + "/hubs/rtm", {
|
|
25
|
+
accessTokenFactory: this.tokenFactory
|
|
26
|
+
})
|
|
27
|
+
.withAutomaticReconnect()
|
|
28
|
+
.build();
|
|
29
|
+
|
|
30
|
+
this.isConnectionStarted = this.connection.start();
|
|
31
|
+
|
|
32
|
+
this.connection.onclose(error => this.triggerHandler(this.EVENT_CLOSE, error));
|
|
33
|
+
this.connection.onreconnecting(error => this.triggerHandler(this.EVENT_RECONNECTING, error));
|
|
34
|
+
this.connection.onreconnected(connectionId => this.triggerHandler(this.EVENT_RECONNECTED, connectionId));
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async subscribe(group: string, event: string, callback: any) {
|
|
40
|
+
await this.isConnectionStarted;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
var name = group ? group + ":" + event : event;
|
|
44
|
+
await this.connection.invoke("AddToGroup", name);
|
|
45
|
+
this.groups.push(name);
|
|
46
|
+
this.connection.on(name, callback);
|
|
47
|
+
} catch(err: any){
|
|
48
|
+
console.warn("Error in AddToGroup:", err)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async unsubscribe(group: string, event: string, callback: any) {
|
|
54
|
+
await this.isConnectionStarted;
|
|
55
|
+
var name = group ? group + ":" + event : event;
|
|
56
|
+
|
|
57
|
+
// get first occurence of group name and remove it
|
|
58
|
+
const index = this.groups.findIndex(e => e === name);
|
|
59
|
+
if(index !== -1){
|
|
60
|
+
this.groups = this.groups.splice(index, 1);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// if no more groups, remove from server
|
|
64
|
+
if(!this.groups.find(e => e === name)){
|
|
65
|
+
await this.connection.invoke("RemoveFromGroup", name);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
} catch(err: any){
|
|
69
|
+
console.warn("Error in RemoveFromGroup:", err)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.connection.off(name, callback);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
triggerHandler(name: string, ...data: any) {
|
|
77
|
+
name = name.endsWith(this.EVENT_NAMESPACE) ? name : name + this.EVENT_NAMESPACE;
|
|
78
|
+
let event = new CustomEvent(name, { cancelable: false });
|
|
79
|
+
|
|
80
|
+
console.debug("triggerHandler", name);
|
|
81
|
+
|
|
82
|
+
this.connectionEvents.forEach((eventHandler) => {
|
|
83
|
+
if (eventHandler.name === name) {
|
|
84
|
+
eventHandler.handler(event, ...data);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (name === this.EVENT_RECONNECTED + this.EVENT_NAMESPACE) {
|
|
89
|
+
// re-add to signalr groups after reconnect
|
|
90
|
+
for (var i = 0; i < this.groups.length; i++) {
|
|
91
|
+
this.connection.invoke("AddToGroup", this.groups[i]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Icon from "../ui/Icon";
|
|
3
|
+
import { fileSizeAsString, getIcon } from "../utils/fileUtilities";
|
|
4
|
+
import { prefix as wy } from "../utils/styles";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
previewFormat: string,
|
|
8
|
+
url: string,
|
|
9
|
+
previewUrl: string,
|
|
10
|
+
mediaType: string,
|
|
11
|
+
name: string,
|
|
12
|
+
kind: string,
|
|
13
|
+
size: number,
|
|
14
|
+
provider: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Attachment = ({ previewFormat, url, previewUrl, mediaType, name, kind, size, provider }: Props) => {
|
|
18
|
+
let fileSize = size > 0 ? fileSizeAsString(size) : null;
|
|
19
|
+
let { icon, color } = getIcon(name, mediaType)
|
|
20
|
+
return (
|
|
21
|
+
<a href={previewUrl || url} className={wy('attachment')} target={"_blank"} title={name}>
|
|
22
|
+
<div className={wy('attachment-icon')} title={kind}><Icon.UI name={icon} color={color} size={2} /></div>
|
|
23
|
+
<div className={wy('attachment-content')}>
|
|
24
|
+
<div className={wy('attachment-title')}>{name}</div>
|
|
25
|
+
{fileSize &&
|
|
26
|
+
<div className={wy('attachment-meta')} title={fileSize}>{fileSize}</div>
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
</a>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default Attachment;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import Presence from "./Presence";
|
|
4
|
+
import { prefix as wy } from "../utils/styles";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
id?: number,
|
|
8
|
+
name: string,
|
|
9
|
+
src: string
|
|
10
|
+
presence?: string,
|
|
11
|
+
size?: number,
|
|
12
|
+
className?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Avatar = ({ id, src, name, presence, size = 48, className }: Props) => {
|
|
16
|
+
return (
|
|
17
|
+
<div className={classNames(wy('avatar-presence'), className)}>
|
|
18
|
+
<img alt="" title={name} className={wy('avatar')} height={size} width={size} src={src} />
|
|
19
|
+
{presence && id &&
|
|
20
|
+
<Presence id={id} status={presence} />
|
|
21
|
+
}
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default Avatar;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { WeavyContext } from '../contexts/WeavyContext';
|
|
3
|
+
import { ChatProps } from '../types/Chat';
|
|
4
|
+
import useChat from '../hooks/useChat';
|
|
5
|
+
import Messages from './Messages';
|
|
6
|
+
import useMembers from '../hooks/useMembers';
|
|
7
|
+
import Typing from './Typing';
|
|
8
|
+
import useConversation from '../hooks/useConversation';
|
|
9
|
+
import { prefix as wy } from "../utils/styles";
|
|
10
|
+
|
|
11
|
+
const Chat = ({ id }: ChatProps) => {
|
|
12
|
+
const { client } = useContext(WeavyContext);
|
|
13
|
+
const [selectedId, setSelectedId] = useState<number | null>(null)
|
|
14
|
+
|
|
15
|
+
if (!client) {
|
|
16
|
+
throw new Error('Weavy Chat component must be used within an WeavyProvider');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { isLoading: isLoadingChat, data: dataChat } = useChat(id, {});
|
|
20
|
+
|
|
21
|
+
const { isLoading: isLoadingMembers, data: dataMembers } = useMembers(selectedId, {
|
|
22
|
+
// The query will not execute until the activeConversation exists
|
|
23
|
+
enabled: selectedId != null
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const { isLoading: isLoadingConversation, data: dataConversation } = useConversation(selectedId, {
|
|
27
|
+
// The query will not execute until the activeConversation exists
|
|
28
|
+
enabled: selectedId != null
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (dataChat) {
|
|
33
|
+
setSelectedId(dataChat.id);
|
|
34
|
+
} else {
|
|
35
|
+
setSelectedId(null);
|
|
36
|
+
}
|
|
37
|
+
}, [dataChat]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<header className={wy('appbars')}>
|
|
42
|
+
<nav className={wy('appbar')}>
|
|
43
|
+
|
|
44
|
+
{selectedId && dataConversation &&
|
|
45
|
+
|
|
46
|
+
<>
|
|
47
|
+
<div>
|
|
48
|
+
<Typing id={selectedId} context="conversation">
|
|
49
|
+
{dataConversation.display_name}
|
|
50
|
+
</Typing>
|
|
51
|
+
</div>
|
|
52
|
+
</>
|
|
53
|
+
}
|
|
54
|
+
</nav>
|
|
55
|
+
</header>
|
|
56
|
+
|
|
57
|
+
{!isLoadingChat && !dataChat &&
|
|
58
|
+
<div>No chat with the contextual id <strong>{id}</strong></div>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
{selectedId && dataMembers &&
|
|
62
|
+
<Messages id={selectedId} members={dataMembers} />
|
|
63
|
+
}
|
|
64
|
+
</>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default Chat;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { useQueryClient } from 'react-query';
|
|
3
|
+
import { MessengerContext } from '../contexts/MessengerContext';
|
|
4
|
+
import { WeavyContext } from '../contexts/WeavyContext';
|
|
5
|
+
import useMembers from '../hooks/useMembers';
|
|
6
|
+
import { ConversationProps } from '../types/Conversation';
|
|
7
|
+
import Typing from './Typing';
|
|
8
|
+
import Dropdown from '../ui/Dropdown';
|
|
9
|
+
import Icon from '../ui/Icon';
|
|
10
|
+
import Button from '../ui/Button';
|
|
11
|
+
import Overlay from '../ui/Overlay';
|
|
12
|
+
import SearchUsers from './SearchUsers';
|
|
13
|
+
import useMutateMembers from '../hooks/useMutateMembers';
|
|
14
|
+
import useConversation from '../hooks/useConversation';
|
|
15
|
+
import useMutateConversationName from '../hooks/useMutateConversationName';
|
|
16
|
+
import { prefix as wy } from "../utils/styles";
|
|
17
|
+
import useMutateRemoveMembers from '../hooks/useMutateRemoveMembers';
|
|
18
|
+
import Avatar from './Avatar';
|
|
19
|
+
import { UserContext } from '../contexts/UserContext';
|
|
20
|
+
import Messages from './Messages';
|
|
21
|
+
|
|
22
|
+
const Conversation = ({ id, showBackButton }: ConversationProps) => {
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
const queryClient = useQueryClient();
|
|
26
|
+
const { client } = useContext(WeavyContext);
|
|
27
|
+
const { selectedConversationId, setSelectedConversationId } = useContext(MessengerContext);
|
|
28
|
+
const { user } = useContext(UserContext);
|
|
29
|
+
const [modalAddOpen, setModalAddOpen] = useState(false);
|
|
30
|
+
const [modalDetailsOpen, setModalDetailsOpen] = useState(false);
|
|
31
|
+
const [title, setTitle] = useState<string>("");
|
|
32
|
+
|
|
33
|
+
const ChatRoom = "edb400ac-839b-45a7-b2a8-6a01820d1c44";
|
|
34
|
+
|
|
35
|
+
if (!client) {
|
|
36
|
+
throw new Error('Weavy Conversation component must be used within an WeavyProvider');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { isLoading: isLoadingConversation, data: dataConversation } = useConversation(selectedConversationId, {
|
|
40
|
+
// The query will not execute until the activeConversation exists
|
|
41
|
+
enabled: selectedConversationId != null
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const { isLoading: isLoadingMembers, data: dataMembers } = useMembers(selectedConversationId, {
|
|
45
|
+
// The query will not execute until the activeConversation exists
|
|
46
|
+
enabled: selectedConversationId != null
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// react-query (mutation)
|
|
50
|
+
|
|
51
|
+
const addMembersMutation = useMutateMembers();
|
|
52
|
+
const updateNameMutation = useMutateConversationName();
|
|
53
|
+
const removeMembers = useMutateRemoveMembers();
|
|
54
|
+
|
|
55
|
+
const handleRealtimeAppUpdated = useCallback((data: ConversationType) => {
|
|
56
|
+
if (data.id !== selectedConversationId) return;
|
|
57
|
+
queryClient.invalidateQueries(['conversation', selectedConversationId]);
|
|
58
|
+
}, [selectedConversationId]);
|
|
59
|
+
|
|
60
|
+
const handleAdd = async (selected: UserType[]) => {
|
|
61
|
+
|
|
62
|
+
const membersList = selected.map((m) => m.id);
|
|
63
|
+
await addMembersMutation.mutateAsync({ id: selectedConversationId, members: membersList });
|
|
64
|
+
setModalAddOpen(false);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const toggleAddModal = (open: boolean) => {
|
|
68
|
+
setModalAddOpen(open);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const toggleDetailsModal = (open: boolean) => {
|
|
72
|
+
setModalDetailsOpen(open);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const handleUpdateTitle = (e: any) => {
|
|
76
|
+
setTitle(e.target.value);
|
|
77
|
+
updateNameMutation.mutate({ id: selectedConversationId, name: e.target.value });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const handleLeaveConversation = () => {
|
|
81
|
+
removeMembers.mutate({ id: selectedConversationId, members: [user.id] });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const handleBack = () => {
|
|
85
|
+
setSelectedConversationId(null);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
// set selected conversation id if id is supplied to component
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (id) {
|
|
95
|
+
setSelectedConversationId(id);
|
|
96
|
+
}
|
|
97
|
+
}, [id]);
|
|
98
|
+
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
|
|
101
|
+
if (selectedConversationId) {
|
|
102
|
+
client.subscribe(`a${selectedConversationId}`, "app-updated", handleRealtimeAppUpdated);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return () => {
|
|
106
|
+
|
|
107
|
+
if (selectedConversationId) {
|
|
108
|
+
|
|
109
|
+
client.unsubscribe(`a${selectedConversationId}`, "app-updated", handleRealtimeAppUpdated);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, [selectedConversationId]);
|
|
113
|
+
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (dataConversation && dataConversation.type === ChatRoom) {
|
|
116
|
+
setTitle(dataConversation?.display_name);
|
|
117
|
+
}
|
|
118
|
+
}, [dataConversation]);
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<>
|
|
125
|
+
<header className={wy('appbars')}>
|
|
126
|
+
<nav className={wy('appbar')}>
|
|
127
|
+
<div>
|
|
128
|
+
{showBackButton &&
|
|
129
|
+
<Button.UI onClick={handleBack}><Icon.UI name="back" /></Button.UI>
|
|
130
|
+
}</div>
|
|
131
|
+
{selectedConversationId && dataConversation &&
|
|
132
|
+
|
|
133
|
+
<>
|
|
134
|
+
<div>
|
|
135
|
+
<Typing id={selectedConversationId} context="conversation">
|
|
136
|
+
{dataConversation.display_name}
|
|
137
|
+
</Typing>
|
|
138
|
+
</div>
|
|
139
|
+
<Dropdown.UI directionX='left'>
|
|
140
|
+
|
|
141
|
+
<Dropdown.Item onClick={() => toggleDetailsModal(true)}>Details</Dropdown.Item>
|
|
142
|
+
|
|
143
|
+
{dataConversation.type === ChatRoom &&
|
|
144
|
+
<>
|
|
145
|
+
<Dropdown.Item onClick={() => toggleAddModal(true)}>Add people</Dropdown.Item>
|
|
146
|
+
<Dropdown.Item onClick={handleLeaveConversation}>Leave conversation</Dropdown.Item>
|
|
147
|
+
</>
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
</Dropdown.UI>
|
|
151
|
+
</>
|
|
152
|
+
}
|
|
153
|
+
</nav>
|
|
154
|
+
</header>
|
|
155
|
+
|
|
156
|
+
{!selectedConversationId &&
|
|
157
|
+
<div className={wy('avatar-header')}>
|
|
158
|
+
<Avatar src={user.avatar_url} name={user.title} presence={user.presence} id={user.id} size={256} />
|
|
159
|
+
<h2>Welcome {user.name}!</h2>
|
|
160
|
+
Select a conversation to get started
|
|
161
|
+
</div>
|
|
162
|
+
}
|
|
163
|
+
{selectedConversationId && dataMembers &&
|
|
164
|
+
<Messages id={selectedConversationId} members={dataMembers} displayName={dataConversation?.display_name} avatarUrl={dataConversation?.avatar_url} />
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
<Overlay.UI isOpen={modalAddOpen} className={wy('modal')}>
|
|
168
|
+
<header className={wy('appbars')}>
|
|
169
|
+
<nav className={wy('appbar')}>
|
|
170
|
+
<Button.UI onClick={() => toggleAddModal(false)}><Icon.UI name='close' /></Button.UI>
|
|
171
|
+
<div className={wy('appbar-text')}>Add people</div>
|
|
172
|
+
</nav>
|
|
173
|
+
</header>
|
|
174
|
+
<SearchUsers handleSubmit={handleAdd} buttonTitle="Add selected" />
|
|
175
|
+
</Overlay.UI>
|
|
176
|
+
|
|
177
|
+
<Overlay.UI isOpen={modalDetailsOpen} className={wy('modal')}>
|
|
178
|
+
<header className={wy('appbars')}>
|
|
179
|
+
<nav className={wy('appbar')}>
|
|
180
|
+
<Button.UI onClick={() => toggleDetailsModal(false)}><Icon.UI name='close' /></Button.UI>
|
|
181
|
+
<div className={wy('appbar-text')}>Conversation details</div>
|
|
182
|
+
</nav>
|
|
183
|
+
</header>
|
|
184
|
+
<div>
|
|
185
|
+
{dataConversation && <div className={wy('avatar-header')}><Avatar src={dataConversation?.avatar_url} name={title} size={128} /></div>}
|
|
186
|
+
{dataConversation?.type !== ChatRoom &&
|
|
187
|
+
<h4 className={wy('avatar-display-name')}>{dataConversation?.display_name}</h4>
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
{dataConversation?.type === ChatRoom && (
|
|
191
|
+
<>
|
|
192
|
+
<div className={wy('pane-group')}>
|
|
193
|
+
<input className={wy('input')} value={title} onChange={(e) => handleUpdateTitle(e)} />
|
|
194
|
+
</div>
|
|
195
|
+
<div className={wy('pane-group')}>
|
|
196
|
+
<table className={wy('search-result-table')}>
|
|
197
|
+
<tbody>
|
|
198
|
+
{dataMembers?.data.map((m: MemberType) => {
|
|
199
|
+
return (
|
|
200
|
+
<tr key={m.id} className={wy('search-result-table-checkbox')}>
|
|
201
|
+
<td className={wy('search-result-table-icon')}><Avatar src={m.avatar_url} name={m.display_name} id={m.id} size={24} presence={m.presence} /></td>
|
|
202
|
+
<td>{m.display_name}</td>
|
|
203
|
+
<td></td>
|
|
204
|
+
</tr>
|
|
205
|
+
)
|
|
206
|
+
})}
|
|
207
|
+
</tbody>
|
|
208
|
+
</table>
|
|
209
|
+
</div>
|
|
210
|
+
</>
|
|
211
|
+
)}
|
|
212
|
+
</div>
|
|
213
|
+
</Overlay.UI>
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
</>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export default React.memo(Conversation);
|