@weavy/uikit-react 12.1.0 → 13.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.
Files changed (86) hide show
  1. package/changelog.md +36 -0
  2. package/dist/cjs/index.js +28 -6
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/client/WeavyClient.d.ts +8 -1
  5. package/dist/cjs/types/components/Attachment.d.ts +2 -1
  6. package/dist/cjs/types/components/Chat.d.ts +1 -1
  7. package/dist/cjs/types/components/PdfViewer.d.ts +3 -1
  8. package/dist/cjs/types/components/Preview.d.ts +8 -10
  9. package/dist/cjs/types/contexts/PreviewContext.d.ts +2 -1
  10. package/dist/cjs/types/contexts/WeavyContext.d.ts +2 -3
  11. package/dist/cjs/types/types/Chat.d.ts +1 -1
  12. package/dist/cjs/types/types/types.d.ts +16 -5
  13. package/dist/cjs/types/ui/Spinner.d.ts +9 -0
  14. package/dist/cjs/types/utils/fileUtilities.d.ts +1 -4
  15. package/dist/css/weavy-chat.css +270 -94
  16. package/dist/css/weavy-messenger.css +274 -96
  17. package/dist/css/weavy.css +274 -96
  18. package/dist/esm/index.js +28 -6
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/types/client/WeavyClient.d.ts +8 -1
  21. package/dist/esm/types/components/Attachment.d.ts +2 -1
  22. package/dist/esm/types/components/Chat.d.ts +1 -1
  23. package/dist/esm/types/components/PdfViewer.d.ts +3 -1
  24. package/dist/esm/types/components/Preview.d.ts +8 -10
  25. package/dist/esm/types/contexts/PreviewContext.d.ts +2 -1
  26. package/dist/esm/types/contexts/WeavyContext.d.ts +2 -3
  27. package/dist/esm/types/types/Chat.d.ts +1 -1
  28. package/dist/esm/types/types/types.d.ts +16 -5
  29. package/dist/esm/types/ui/Spinner.d.ts +9 -0
  30. package/dist/esm/types/utils/fileUtilities.d.ts +1 -4
  31. package/dist/index.d.ts +14 -7
  32. package/package.json +2 -2
  33. package/rollup.config.js +3 -1
  34. package/src/client/WeavyClient.ts +105 -24
  35. package/src/components/Attachment.tsx +8 -7
  36. package/src/components/Chat.tsx +3 -3
  37. package/src/components/Conversation.tsx +3 -3
  38. package/src/components/Message.tsx +1 -1
  39. package/src/components/Messages.tsx +1 -1
  40. package/src/components/PdfViewer.tsx +88 -83
  41. package/src/components/Preview.tsx +115 -54
  42. package/src/components/SearchUsers.tsx +2 -2
  43. package/src/contexts/PreviewContext.tsx +90 -16
  44. package/src/contexts/WeavyContext.tsx +7 -4
  45. package/src/hooks/useBadge.ts +2 -6
  46. package/src/hooks/useChat.ts +3 -14
  47. package/src/hooks/useConversation.ts +1 -7
  48. package/src/hooks/useConversations.ts +1 -7
  49. package/src/hooks/useFileUploader.ts +6 -8
  50. package/src/hooks/useMembers.ts +1 -7
  51. package/src/hooks/useMessages.ts +1 -7
  52. package/src/hooks/useMutateChat.ts +6 -11
  53. package/src/hooks/useMutateConversation.ts +7 -10
  54. package/src/hooks/useMutateConversationName.ts +10 -12
  55. package/src/hooks/useMutateDeleteReaction.ts +3 -8
  56. package/src/hooks/useMutateExternalBlobs.ts +6 -11
  57. package/src/hooks/useMutateMeeting.ts +6 -11
  58. package/src/hooks/useMutateMembers.ts +8 -13
  59. package/src/hooks/useMutateMessage.ts +10 -15
  60. package/src/hooks/useMutatePinned.ts +3 -8
  61. package/src/hooks/useMutateReaction.ts +6 -12
  62. package/src/hooks/useMutateRead.ts +1 -10
  63. package/src/hooks/useMutateRemoveMembers.ts +7 -12
  64. package/src/hooks/useMutateTyping.ts +6 -11
  65. package/src/hooks/useSearchUsers.ts +1 -6
  66. package/src/hooks/useUser.ts +3 -14
  67. package/src/scss/theme/_appbar.scss +4 -2
  68. package/src/scss/theme/_cm-editor.scss +1 -1
  69. package/src/scss/theme/_code-vscode-dark.scss +184 -0
  70. package/src/scss/theme/_code-vscode-light.scss +179 -0
  71. package/src/scss/theme/_code.scss +9 -112
  72. package/src/scss/theme/_files.scss +1 -1
  73. package/src/scss/theme/_message-editor.scss +1 -1
  74. package/src/scss/theme/_overlays.scss +2 -2
  75. package/src/scss/theme/_panels.scss +11 -7
  76. package/src/scss/theme/_preview-code.scss +5 -0
  77. package/src/scss/theme/_preview-embed.scss +3 -3
  78. package/src/scss/theme/_preview-image.scss +1 -1
  79. package/src/scss/theme/_preview-text.scss +1 -1
  80. package/src/scss/theme/_preview.scss +7 -2
  81. package/src/scss/weavy-chat.scss +1 -0
  82. package/src/scss/weavy-messenger.scss +1 -0
  83. package/src/types/Chat.ts +1 -1
  84. package/src/types/types.ts +16 -5
  85. package/src/ui/Spinner.tsx +18 -0
  86. package/src/utils/fileUtilities.ts +11 -125
@@ -1,16 +1,23 @@
1
1
  export default class WeavyClient {
2
2
  url: string;
3
- tokenFactory: () => string | Promise<string>;
4
3
  connection: import("@microsoft/signalr").HubConnection;
4
+ tokenFactory: (refresh: boolean) => Promise<string>;
5
5
  groups: string[];
6
6
  connectionEvents: any[];
7
7
  isConnectionStarted: any;
8
+ token: string;
9
+ tokenPromise: Promise<string> | null;
8
10
  EVENT_NAMESPACE: string;
9
11
  EVENT_CLOSE: string;
10
12
  EVENT_RECONNECTING: string;
11
13
  EVENT_RECONNECTED: string;
12
14
  constructor(options: WeavyClientOptions);
15
+ get(url: string, retry?: boolean): Promise<Response>;
16
+ post(url: string, method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH", body: string | FormData, contentType?: string, retry?: boolean): Promise<Response>;
17
+ getToken(refresh: boolean): Promise<string>;
18
+ tokenFactoryInternal(refresh?: boolean, fromSR?: boolean): Promise<string>;
13
19
  subscribe(group: string, event: string, callback: any): Promise<void>;
14
20
  unsubscribe(group: string, event: string, callback: any): Promise<void>;
21
+ destroy(): void;
15
22
  triggerHandler(name: string, ...data: any): void;
16
23
  }
@@ -8,6 +8,7 @@ declare type Props = {
8
8
  kind: string;
9
9
  size: number;
10
10
  provider: string;
11
+ onClick?: (e: any) => void;
11
12
  };
12
- declare const Attachment: ({ previewFormat, url, previewUrl, mediaType, name, kind, size, provider }: Props) => JSX.Element;
13
+ declare const Attachment: ({ previewFormat, url, previewUrl, mediaType, name, kind, size, provider, onClick }: Props) => JSX.Element;
13
14
  export default Attachment;
@@ -1,4 +1,4 @@
1
1
  /// <reference types="react" />
2
2
  import { ChatProps } from '../types/Chat';
3
- declare const Chat: ({ id }: ChatProps) => JSX.Element;
3
+ declare const Chat: ({ uid }: ChatProps) => JSX.Element;
4
4
  export default Chat;
@@ -1,6 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  declare type Props = {
3
3
  src: string;
4
+ pdfCMapsUrl: string;
5
+ pdfWorkerUrl: string;
4
6
  };
5
- declare const PdfViewer: ({ src }: Props) => JSX.Element;
7
+ declare const PdfViewer: ({ src, pdfCMapsUrl, pdfWorkerUrl }: Props) => JSX.Element;
6
8
  export default PdfViewer;
@@ -7,20 +7,16 @@ declare type ImageProps = {
7
7
  export declare const PreviewImage: ({ src, width, height }: ImageProps) => JSX.Element;
8
8
  declare type DocumentProps = {
9
9
  src: string;
10
+ client: any;
10
11
  };
11
- export declare const PreviewDocument: ({ src }: DocumentProps) => JSX.Element;
12
- declare type VideoProps = {
12
+ export declare const PreviewDocument: ({ src, client }: DocumentProps) => JSX.Element;
13
+ declare type MediaProps = {
14
+ format: string;
13
15
  src: string;
14
16
  name: string;
15
17
  mediaType?: string;
16
18
  };
17
- export declare const PreviewVideo: ({ src, name, mediaType }: VideoProps) => JSX.Element;
18
- declare type AudioProps = {
19
- src: string;
20
- name: string;
21
- mediaType?: string;
22
- };
23
- export declare const PreviewAudio: ({ src, name, mediaType }: AudioProps) => JSX.Element;
19
+ export declare const PreviewMedia: ({ format, src, name, mediaType }: MediaProps) => JSX.Element;
24
20
  declare type TextProps = {
25
21
  src: string;
26
22
  html?: boolean;
@@ -45,7 +41,9 @@ declare type IconProps = {
45
41
  };
46
42
  export declare const PreviewIcon: ({ children, src, icon, name, provider, download, className }: IconProps) => JSX.Element;
47
43
  declare type PreviewProps = {
44
+ client: any;
48
45
  src: string;
46
+ link?: string;
49
47
  format: PreviewFormatType;
50
48
  name: string;
51
49
  icon: string;
@@ -54,5 +52,5 @@ declare type PreviewProps = {
54
52
  mediaType?: string;
55
53
  provider?: string;
56
54
  };
57
- export declare const Preview: ({ src, format, name, icon, width, height, mediaType, provider }: PreviewProps) => JSX.Element;
55
+ export declare const Preview: ({ client, src, link, format, name, icon, width, height, mediaType, provider }: PreviewProps) => JSX.Element;
58
56
  export default Preview;
@@ -1,7 +1,8 @@
1
1
  import React from "react";
2
2
  export declare const PreviewContext: React.Context<PreviewContextProps>;
3
3
  declare type Props = {
4
+ client: any;
4
5
  children: React.ReactNode;
5
6
  };
6
- declare const PreviewProvider: ({ children }: Props) => JSX.Element;
7
+ declare const PreviewProvider: ({ client, children }: Props) => JSX.Element;
7
8
  export default PreviewProvider;
@@ -1,10 +1,9 @@
1
1
  import React from "react";
2
- import WeavyClient from "../client/WeavyClient";
3
2
  export declare const WeavyContext: React.Context<WeavyContextProps>;
4
- declare type Props = {
3
+ declare type WeavyProviderProperties = {
5
4
  children: React.ReactNode;
6
5
  client: WeavyClient;
7
6
  options?: WeavyContextOptions;
8
7
  };
9
- declare const WeavyProvider: ({ children, client, options }: Props) => JSX.Element;
8
+ declare const WeavyProvider: ({ children, client, options }: WeavyProviderProperties) => JSX.Element;
10
9
  export default WeavyProvider;
@@ -1,3 +1,3 @@
1
1
  export interface ChatProps {
2
- id: string;
2
+ uid: string;
3
3
  }
@@ -1,13 +1,16 @@
1
1
  /// <reference types="react" />
2
2
  interface WeavyClient {
3
3
  url: string;
4
- tokenFactory: (() => string | Promise<string>);
4
+ tokenFactoryInternal: () => Promise<string>;
5
5
  subscribe: Function;
6
6
  unsubscribe: Function;
7
+ destroy: Function;
8
+ get: (url: string, retry?: boolean) => Promise<Response>;
9
+ post: (url: string, method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH", body: string | FormData, contentType?: string, retry?: boolean) => Promise<Response>;
7
10
  }
8
11
  declare type WeavyClientOptions = {
9
12
  url: string;
10
- tokenFactory: (() => string | Promise<string>);
13
+ tokenFactory: (refresh: boolean) => Promise<string>;
11
14
  };
12
15
  declare type WeavyContextProps = {
13
16
  client: WeavyClient | null;
@@ -19,6 +22,8 @@ declare type WeavyContextOptions = {
19
22
  enableCloudFiles?: boolean;
20
23
  enableScrollbarDetection?: boolean;
21
24
  filebrowserUrl?: string;
25
+ pdfWorkerUrl?: string;
26
+ pdfCMapsUrl?: string;
22
27
  reactions?: string[];
23
28
  };
24
29
  declare type MessengerContextProps = {
@@ -114,11 +119,17 @@ declare type AttachmentType = {
114
119
  size: number;
115
120
  provider: string;
116
121
  download_url: string;
117
- preview_url: string;
118
- thumbnail_url: string;
122
+ embed_url: string;
119
123
  external_url: string;
124
+ thumbnail_url: string;
125
+ preview_format: PreviewFormatType;
126
+ application_url: string;
127
+ preview_url: string;
128
+ created_at: string;
129
+ created_by?: UserType;
130
+ createdById?: number;
120
131
  };
121
- declare type PreviewFormatType = "text" | "code" | "markup" | "image" | "video" | "audio" | "document" | "embed" | "link" | "download" | "none";
132
+ declare type PreviewFormatType = "audio" | "code" | "embed" | "html" | "image" | "pdf" | "text" | "video" | "none";
122
133
  declare type ReactionType = {
123
134
  id: number;
124
135
  parent: MessageType;
@@ -0,0 +1,9 @@
1
+ /// <reference types="react" />
2
+ declare type SpinnerProps = {
3
+ size?: number;
4
+ spin?: boolean;
5
+ };
6
+ declare const UISpinner: {
7
+ UI: ({ spin, size }: SpinnerProps) => JSX.Element;
8
+ };
9
+ export default UISpinner;
@@ -6,15 +6,12 @@ export declare function isWebImage(path: string): boolean;
6
6
  export declare function isBitmap(path: string): boolean;
7
7
  export declare function isMetaFile(path: string): boolean;
8
8
  export declare function isVideo(ext: string): boolean;
9
+ export declare function isMarkdown(ext: string): boolean;
9
10
  export declare function isMarkup(ext: string): boolean;
10
11
  export declare function isCode(ext: string): boolean;
11
12
  export declare function isText(ext: string): boolean;
12
13
  export declare function isOfficeDocument(path: string): boolean;
13
- export declare function canResize(path: string): boolean;
14
- export declare function canConvertToImage(filename: string): boolean;
15
- export declare function canConvertToPdf(filename: string): boolean;
16
14
  export declare function getIcon(name: string, mediaType?: string): {
17
15
  icon: string;
18
16
  color?: string;
19
17
  };
20
- export declare function getPreviewFormat(filename: string): PreviewFormatType;
package/dist/index.d.ts CHANGED
@@ -3,30 +3,37 @@ import * as _microsoft_signalr from '@microsoft/signalr';
3
3
  import React, { FC } from 'react';
4
4
  import { Styles } from 'react-modal';
5
5
 
6
- declare class WeavyClient {
6
+ declare class WeavyClient$1 {
7
7
  url: string;
8
- tokenFactory: () => string | Promise<string>;
9
8
  connection: _microsoft_signalr.HubConnection;
9
+ tokenFactory: (refresh: boolean) => Promise<string>;
10
10
  groups: string[];
11
11
  connectionEvents: any[];
12
12
  isConnectionStarted: any;
13
+ token: string;
14
+ tokenPromise: Promise<string> | null;
13
15
  EVENT_NAMESPACE: string;
14
16
  EVENT_CLOSE: string;
15
17
  EVENT_RECONNECTING: string;
16
18
  EVENT_RECONNECTED: string;
17
19
  constructor(options: WeavyClientOptions);
20
+ get(url: string, retry?: boolean): Promise<Response>;
21
+ post(url: string, method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH", body: string | FormData, contentType?: string, retry?: boolean): Promise<Response>;
22
+ getToken(refresh: boolean): Promise<string>;
23
+ tokenFactoryInternal(refresh?: boolean, fromSR?: boolean): Promise<string>;
18
24
  subscribe(group: string, event: string, callback: any): Promise<void>;
19
25
  unsubscribe(group: string, event: string, callback: any): Promise<void>;
26
+ destroy(): void;
20
27
  triggerHandler(name: string, ...data: any): void;
21
28
  }
22
29
 
23
30
  declare const WeavyContext: React.Context<WeavyContextProps>;
24
- declare type Props$2 = {
31
+ declare type WeavyProviderProperties = {
25
32
  children: React.ReactNode;
26
33
  client: WeavyClient;
27
34
  options?: WeavyContextOptions;
28
35
  };
29
- declare const WeavyProvider: ({ children, client, options }: Props$2) => JSX.Element;
36
+ declare const WeavyProvider: ({ children, client, options }: WeavyProviderProperties) => JSX.Element;
30
37
 
31
38
  declare const MessengerContext: React.Context<MessengerContextProps>;
32
39
  declare type Props$1 = {
@@ -48,10 +55,10 @@ interface ConversationProps {
48
55
  declare const _default: React.MemoExoticComponent<({ id, showBackButton }: ConversationProps) => JSX.Element>;
49
56
 
50
57
  interface ChatProps {
51
- id: string;
58
+ uid: string;
52
59
  }
53
60
 
54
- declare const Chat: ({ id }: ChatProps) => JSX.Element;
61
+ declare const Chat: ({ uid }: ChatProps) => JSX.Element;
55
62
 
56
63
  declare const UIButton: {
57
64
  UI: any;
@@ -94,4 +101,4 @@ declare const UIOverlay: {
94
101
  UI: ({ children, className, isOpen, style }: OverlayProps) => JSX.Element;
95
102
  };
96
103
 
97
- 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 };
104
+ export { UIButton as Button, Chat, _default as Conversation, ConversationBadge, ConversationList, UIDropdown as Dropdown, UIIcon as Icon, Messenger, MessengerContext, MessengerProvider, UIOverlay as Overlay, WeavyClient$1 as WeavyClient, WeavyContext, WeavyProvider };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weavy/uikit-react",
3
- "version": "12.1.0",
3
+ "version": "13.0.0",
4
4
  "author": "Weavy",
5
5
  "description": "React UI-kit for Weavy",
6
6
  "homepage": "https://github.com/weavy/weavy-uikit-react",
@@ -50,7 +50,7 @@
50
50
  "emoji-toolkit": "^6.6.0",
51
51
  "lodash.debounce": "^4.0.8",
52
52
  "lodash.throttle": "^4.1.1",
53
- "pdfjs-dist": "^2.14.305",
53
+ "pdfjs-dist": "^2.15.349",
54
54
  "react-modal": "^3.14.4",
55
55
  "react-query": "^3.34.16"
56
56
  }
package/rollup.config.js CHANGED
@@ -24,7 +24,9 @@ export default [
24
24
  ],
25
25
  plugins: [
26
26
  peerDepsExternal(),
27
- resolve(),
27
+ resolve({
28
+ browser: true
29
+ }),
28
30
  commonjs(),
29
31
  typescript({ tsconfig: "./tsconfig.json" }),
30
32
  terser(),
@@ -2,77 +2,158 @@ import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
2
2
 
3
3
  export default class WeavyClient {
4
4
  url;
5
- tokenFactory;
6
5
  connection;
7
- groups: string[];
8
- connectionEvents: any[];
6
+ tokenFactory;
7
+ groups: string[] = [];
8
+ connectionEvents: any[] = [];
9
9
  isConnectionStarted: any;
10
-
10
+ token: string = "";
11
+ tokenPromise: Promise<string> | null;
11
12
  EVENT_NAMESPACE = ".connection";
12
13
  EVENT_CLOSE = "close";
13
14
  EVENT_RECONNECTING = "reconnecting";
14
15
  EVENT_RECONNECTED = "reconnected";
15
16
 
17
+
16
18
  constructor(options: WeavyClientOptions) {
17
19
  this.url = options.url;
18
- this.tokenFactory = options.tokenFactory
19
- this.groups = [];
20
- this.connectionEvents = [];
21
-
20
+ this.tokenFactory = options.tokenFactory;
21
+ this.tokenPromise = null;
22
22
  this.connection = new HubConnectionBuilder()
23
23
  .configureLogging(LogLevel.None)
24
24
  .withUrl(this.url + "/hubs/rtm", {
25
- accessTokenFactory: this.tokenFactory
25
+ accessTokenFactory: () => { return this.tokenFactoryInternal.call(this, true, true) }
26
26
  })
27
27
  .withAutomaticReconnect()
28
28
  .build();
29
-
30
- this.isConnectionStarted = this.connection.start();
29
+
30
+ this.isConnectionStarted = this.connection.start();
31
31
 
32
32
  this.connection.onclose(error => this.triggerHandler(this.EVENT_CLOSE, error));
33
33
  this.connection.onreconnecting(error => this.triggerHandler(this.EVENT_RECONNECTING, error));
34
34
  this.connection.onreconnected(connectionId => this.triggerHandler(this.EVENT_RECONNECTED, connectionId));
35
-
35
+
36
+ }
37
+
38
+ async get(url: string, retry: boolean = true): Promise<Response> {
39
+ //const token = await this.tokenFactoryInternal();
40
+ //console.log("GET:", url, " - t:", token);
41
+ const response = await fetch(this.url + url, {
42
+ headers: {
43
+ "content-type": "application/json",
44
+ "Authorization": "Bearer " + await this.tokenFactoryInternal()
45
+ }
46
+ });
47
+
48
+ if (!response.ok) {
49
+ if ((response.status === 401 || response.status === 403) && retry) {
50
+ await this.tokenFactoryInternal(true);
51
+ return await this.get(url, false);
52
+ }
53
+
54
+ console.error(`Error calling endpoint ${url}`, response)
55
+ }
56
+
57
+ return response;
36
58
  }
37
59
 
60
+ async post(url: string, method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH", body: string | FormData, contentType: string = "application/json", retry: boolean = true): Promise<Response> {
61
+ let headers: HeadersInit = {
62
+ "Authorization": "Bearer " + await this.tokenFactoryInternal()
63
+ };
64
+
65
+ if(contentType !== ""){
66
+ headers["content-type"] = contentType
67
+ }
68
+ const response = await fetch(this.url + url, {
69
+ method: method,
70
+ body: body,
71
+ headers: headers
72
+ });
73
+
74
+ if (!response.ok) {
75
+ if ((response.status === 401 || response.status === 403) && retry) {
76
+ await this.tokenFactoryInternal(true);
77
+ return await this.post(url, method, body, contentType, false);
78
+ }
38
79
 
39
- async subscribe(group: string, event: string, callback: any) {
80
+ console.error(`Error calling endpoint ${url}`, response)
81
+ }
82
+
83
+ return response;
84
+ }
85
+
86
+ async getToken(refresh: boolean) {
87
+ console.log("Refresh, ", refresh)
88
+ if (!this.token || refresh) {
89
+ console.log("Getting new token...")
90
+ this.token = await this.tokenFactory(true);
91
+ //return await this.tokenFactory(refresh);
92
+ }
93
+ //this.tokenPromise = null;
94
+ console.log("Resolve new token...")
95
+ return this.token;
96
+ }
97
+
98
+ async tokenFactoryInternal(refresh: boolean = false, fromSR: boolean = false): Promise<string> {
99
+ //console.log("Get token with refresh: ", refresh, fromSR)
100
+ if(this.token && !refresh) return this.token;
101
+
102
+ if(!this.tokenPromise){
103
+ //console.log("No ongoing promise, create new one. Refresh: ", refresh)
104
+ this.tokenPromise = this.tokenFactory(refresh);
105
+ let token = await this.tokenPromise;
106
+ //console.log("Got token: ", token)
107
+ this.tokenPromise = null;
108
+ this.token = token;
109
+ return this.token;
110
+ } else{
111
+ //console.log("Already a promise in action, wait for it to resolve...")
112
+ return this.tokenPromise;
113
+ }
114
+ }
115
+
116
+ async subscribe(group: string, event: string, callback: any) {
40
117
  await this.isConnectionStarted;
41
-
118
+
42
119
  try {
43
120
  var name = group ? group + ":" + event : event;
44
121
  await this.connection.invoke("AddToGroup", name);
45
122
  this.groups.push(name);
46
123
  this.connection.on(name, callback);
47
- } catch(err: any){
124
+ } catch (err: any) {
48
125
  console.warn("Error in AddToGroup:", err)
49
126
  }
50
-
127
+
51
128
  }
52
129
 
53
130
  async unsubscribe(group: string, event: string, callback: any) {
54
131
  await this.isConnectionStarted;
55
132
  var name = group ? group + ":" + event : event;
56
-
133
+
57
134
  // get first occurence of group name and remove it
58
135
  const index = this.groups.findIndex(e => e === name);
59
- if(index !== -1){
136
+ if (index !== -1) {
60
137
  this.groups = this.groups.splice(index, 1);
61
138
 
62
- try {
139
+ try {
63
140
  // if no more groups, remove from server
64
- if(!this.groups.find(e => e === name)){
141
+ if (!this.groups.find(e => e === name)) {
65
142
  await this.connection.invoke("RemoveFromGroup", name);
66
143
  }
67
-
68
- } catch(err: any){
144
+
145
+ } catch (err: any) {
69
146
  console.warn("Error in RemoveFromGroup:", err)
70
147
  }
71
148
  }
72
-
149
+
73
150
  this.connection.off(name, callback);
74
151
  }
75
-
152
+
153
+ destroy(){
154
+ this.connection.stop();
155
+ }
156
+
76
157
  triggerHandler(name: string, ...data: any) {
77
158
  name = name.endsWith(this.EVENT_NAMESPACE) ? name : name + this.EVENT_NAMESPACE;
78
159
  let event = new CustomEvent(name, { cancelable: false });
@@ -10,19 +10,20 @@ type Props = {
10
10
  name: string,
11
11
  kind: string,
12
12
  size: number,
13
- provider: string
13
+ provider: string,
14
+ onClick?: (e: any) => void
14
15
  }
15
16
 
16
- const Attachment = ({ previewFormat, url, previewUrl, mediaType, name, kind, size, provider }: Props) => {
17
+ const Attachment = ({ previewFormat, url, previewUrl, mediaType, name, kind, size, provider, onClick }: Props) => {
17
18
  let fileSize = size > 0 ? fileSizeAsString(size) : null;
18
19
  let { icon, color } = getIcon(name, mediaType)
19
20
  return (
20
- <a href={previewUrl || url} className={'wy-attachment'} target={"_blank"} title={name}>
21
- <div className={'wy-attachment-icon'} title={kind}><Icon.UI name={icon} color={color} size={2} /></div>
22
- <div className={'wy-attachment-content'}>
23
- <div className={'wy-attachment-title'}>{name}</div>
21
+ <a href={previewUrl || url} className="wy-attachment" target={"_blank"} title={name} onClick={onClick ? (e) => onClick(e) : undefined}>
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>
24
25
  {fileSize &&
25
- <div className={'wy-attachment-meta'} title={fileSize}>{fileSize}</div>
26
+ <div className="wy-attachment-meta" title={fileSize}>{fileSize}</div>
26
27
  }
27
28
  </div>
28
29
  </a>
@@ -7,7 +7,7 @@ import useMembers from '../hooks/useMembers';
7
7
  import Typing from './Typing';
8
8
  import useConversation from '../hooks/useConversation';
9
9
 
10
- const Chat = ({ id }: ChatProps) => {
10
+ const Chat = ({ uid }: ChatProps) => {
11
11
  const { client } = useContext(WeavyContext);
12
12
  const [selectedId, setSelectedId] = useState<number | null>(null)
13
13
 
@@ -15,7 +15,7 @@ const Chat = ({ id }: ChatProps) => {
15
15
  throw new Error('Weavy Chat component must be used within an WeavyProvider');
16
16
  }
17
17
 
18
- const { isLoading: isLoadingChat, data: dataChat } = useChat(id, {});
18
+ const { isLoading: isLoadingChat, data: dataChat } = useChat(uid, {});
19
19
 
20
20
  const { isLoading: isLoadingMembers, data: dataMembers } = useMembers(selectedId, {
21
21
  // The query will not execute until the activeConversation exists
@@ -51,7 +51,7 @@ const Chat = ({ id }: ChatProps) => {
51
51
  </header>
52
52
 
53
53
  {!isLoadingChat && !dataChat &&
54
- <div>No chat with the contextual id <strong>{id}</strong></div>
54
+ <div>No chat with the contextual id <strong>{uid}</strong></div>
55
55
  }
56
56
 
57
57
  {selectedId && dataMembers &&
@@ -25,7 +25,7 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
25
25
  const { selectedConversationId, setSelectedConversationId } = useContext(MessengerContext);
26
26
  const { user } = useContext(UserContext);
27
27
  const [modalAddOpen, setModalAddOpen] = useState(false);
28
- const [modalDetailsOpen, setModalDetailsOpen] = useState(false);
28
+ const [modalDetailsOpen, setModalDetailsOpen] = useState(false);
29
29
  const [title, setTitle] = useState<string>("");
30
30
 
31
31
  const ChatRoom = "edb400ac-839b-45a7-b2a8-6a01820d1c44";
@@ -186,7 +186,7 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
186
186
  <div className="wy-pane-group">
187
187
  <table className="wy-search-result-table">
188
188
  <tbody>
189
- {dataMembers?.data.map((m: MemberType) => {
189
+ {dataMembers && dataMembers.data && dataMembers.data.map((m: MemberType) => {
190
190
  return (
191
191
  <tr key={m.id} className="wy-search-result-table-checkbox">
192
192
  <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>
@@ -203,7 +203,7 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
203
203
  </div>
204
204
  </Overlay.UI>
205
205
 
206
-
206
+
207
207
  </>
208
208
  )
209
209
  }
@@ -58,7 +58,7 @@ const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_a
58
58
 
59
59
  {files && !!files.length && <div className="wy-attachments">
60
60
  {files.map((a: AttachmentType) =>
61
- <Attachment key={a.id} name={a.name} previewFormat={a.kind} provider={a.provider} url={a.download_url} previewUrl={a.provider ? a.external_url : a.preview_url} mediaType={a.media_type} kind={a.kind} size={a.size} />
61
+ <Attachment key={a.id} onClick={(e) => handlePreviewClick(e, a.id)} name={a.name} previewFormat={a.kind} provider={a.provider} url={a.download_url} previewUrl={a.provider ? a.external_url : a.preview_url} mediaType={a.media_type} kind={a.kind} size={a.size} />
62
62
  )}
63
63
  </div>}
64
64
  </>
@@ -234,7 +234,7 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
234
234
  parentId={id}
235
235
  reactions={item.reactions}
236
236
  //reactions_count={item.reactions_count}
237
- seenBy={members.data.length > 0 ? members.data.filter((member) => {
237
+ seenBy={(members.data && members.data.length > 0) ? members.data.filter((member) => {
238
238
  const hasRead = member.read_at >= item.created_at;
239
239
  const nothingLaterRead = !data.pages.map((p) => p.data).flat().find((message: MessageType) => { return message.id > item.id && member.read_at >= message.created_at });
240
240
  return hasRead && nothingLaterRead && member.id !== user.id;