agora-appbuilder-core 2.3.0-beta.12 → 2.3.0-beta.13
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/package.json +1 -1
- package/template/_package-lock.json +47 -0
- package/template/fpe-api/utils.ts +2 -0
- package/template/package.json +2 -0
- package/template/src/components/ChatContext.ts +10 -3
- package/template/src/components/chat-messages/useChatMessages.tsx +325 -60
- package/template/src/subComponents/ChatBubble.tsx +20 -4
- package/template/src/subComponents/ChatContainer.tsx +8 -2
- package/template/src/utils/getUniqueID.native.ts +6 -0
- package/template/src/utils/getUniqueID.ts +5 -0
- package/template/src/utils/useDeleteMessage.ts +36 -0
- package/template/src/utils/useEditMessage.ts +41 -0
- package/template/src/utils/useSendMessage.ts +4 -5
package/package.json
CHANGED
|
@@ -23,12 +23,14 @@
|
|
|
23
23
|
"electron-updater": "4.3.9",
|
|
24
24
|
"exponential-backoff": "3.1.0",
|
|
25
25
|
"graphql": "15.5.0",
|
|
26
|
+
"nanoid": "4.0.0",
|
|
26
27
|
"nosleep.js": "0.12.0",
|
|
27
28
|
"react": "16.13.1",
|
|
28
29
|
"react-dom": "16.13.1",
|
|
29
30
|
"react-is": "18.0.0",
|
|
30
31
|
"react-native": "0.63.3",
|
|
31
32
|
"react-native-agora": "3.4.2",
|
|
33
|
+
"react-native-get-random-values": "1.8.0",
|
|
32
34
|
"react-native-hyperlink": "0.0.19",
|
|
33
35
|
"react-native-inappbrowser-reborn": "3.5.1",
|
|
34
36
|
"react-native-keep-awake": "4.0.0",
|
|
@@ -12940,6 +12942,11 @@
|
|
|
12940
12942
|
"node": ">= 0.10"
|
|
12941
12943
|
}
|
|
12942
12944
|
},
|
|
12945
|
+
"node_modules/fast-base64-decode": {
|
|
12946
|
+
"version": "1.0.0",
|
|
12947
|
+
"resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
|
|
12948
|
+
"integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="
|
|
12949
|
+
},
|
|
12943
12950
|
"node_modules/fast-deep-equal": {
|
|
12944
12951
|
"version": "3.1.3",
|
|
12945
12952
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
@@ -22140,6 +22147,17 @@
|
|
|
22140
22147
|
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
|
|
22141
22148
|
"optional": true
|
|
22142
22149
|
},
|
|
22150
|
+
"node_modules/nanoid": {
|
|
22151
|
+
"version": "4.0.0",
|
|
22152
|
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
|
|
22153
|
+
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
|
|
22154
|
+
"bin": {
|
|
22155
|
+
"nanoid": "bin/nanoid.js"
|
|
22156
|
+
},
|
|
22157
|
+
"engines": {
|
|
22158
|
+
"node": "^14 || ^16 || >=18"
|
|
22159
|
+
}
|
|
22160
|
+
},
|
|
22143
22161
|
"node_modules/nanomatch": {
|
|
22144
22162
|
"version": "1.2.13",
|
|
22145
22163
|
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
|
@@ -23984,6 +24002,17 @@
|
|
|
23984
24002
|
"react-native": "*"
|
|
23985
24003
|
}
|
|
23986
24004
|
},
|
|
24005
|
+
"node_modules/react-native-get-random-values": {
|
|
24006
|
+
"version": "1.8.0",
|
|
24007
|
+
"resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.8.0.tgz",
|
|
24008
|
+
"integrity": "sha512-H/zghhun0T+UIJLmig3+ZuBCvF66rdbiWUfRSNS6kv5oDSpa1ZiVyvRWtuPesQpT8dXj+Bv7WJRQOUP+5TB1sA==",
|
|
24009
|
+
"dependencies": {
|
|
24010
|
+
"fast-base64-decode": "^1.0.0"
|
|
24011
|
+
},
|
|
24012
|
+
"peerDependencies": {
|
|
24013
|
+
"react-native": ">=0.56"
|
|
24014
|
+
}
|
|
24015
|
+
},
|
|
23987
24016
|
"node_modules/react-native-hyperlink": {
|
|
23988
24017
|
"version": "0.0.19",
|
|
23989
24018
|
"resolved": "https://registry.npmjs.org/react-native-hyperlink/-/react-native-hyperlink-0.0.19.tgz",
|
|
@@ -39247,6 +39276,11 @@
|
|
|
39247
39276
|
"time-stamp": "^1.0.0"
|
|
39248
39277
|
}
|
|
39249
39278
|
},
|
|
39279
|
+
"fast-base64-decode": {
|
|
39280
|
+
"version": "1.0.0",
|
|
39281
|
+
"resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
|
|
39282
|
+
"integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="
|
|
39283
|
+
},
|
|
39250
39284
|
"fast-deep-equal": {
|
|
39251
39285
|
"version": "3.1.3",
|
|
39252
39286
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
@@ -46424,6 +46458,11 @@
|
|
|
46424
46458
|
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
|
|
46425
46459
|
"optional": true
|
|
46426
46460
|
},
|
|
46461
|
+
"nanoid": {
|
|
46462
|
+
"version": "4.0.0",
|
|
46463
|
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
|
|
46464
|
+
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg=="
|
|
46465
|
+
},
|
|
46427
46466
|
"nanomatch": {
|
|
46428
46467
|
"version": "1.2.13",
|
|
46429
46468
|
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
|
@@ -48158,6 +48197,14 @@
|
|
|
48158
48197
|
"integrity": "sha512-zY2BIDCG9vEGQMW9oggsom9XHZJqETG/nafLsZx4z52TzHw9bipNypL/jXpE50Ofg+bS9YKYJaSZGy8M9dgKSA==",
|
|
48159
48198
|
"requires": {}
|
|
48160
48199
|
},
|
|
48200
|
+
"react-native-get-random-values": {
|
|
48201
|
+
"version": "1.8.0",
|
|
48202
|
+
"resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.8.0.tgz",
|
|
48203
|
+
"integrity": "sha512-H/zghhun0T+UIJLmig3+ZuBCvF66rdbiWUfRSNS6kv5oDSpa1ZiVyvRWtuPesQpT8dXj+Bv7WJRQOUP+5TB1sA==",
|
|
48204
|
+
"requires": {
|
|
48205
|
+
"fast-base64-decode": "^1.0.0"
|
|
48206
|
+
}
|
|
48207
|
+
},
|
|
48161
48208
|
"react-native-hyperlink": {
|
|
48162
48209
|
"version": "0.0.19",
|
|
48163
48210
|
"resolved": "https://registry.npmjs.org/react-native-hyperlink/-/react-native-hyperlink-0.0.19.tgz",
|
|
@@ -38,6 +38,8 @@ export {
|
|
|
38
38
|
default as useSendMessage,
|
|
39
39
|
MESSAGE_TYPE,
|
|
40
40
|
} from '../src/utils/useSendMessage';
|
|
41
|
+
export {default as useEditMessage} from '../src/utils/useEditMessage';
|
|
42
|
+
export {default as useDeleteMessage} from '../src/utils/useDeleteMessage';
|
|
41
43
|
export {controlMessageEnum} from '../src/components/ChatContext';
|
|
42
44
|
export {
|
|
43
45
|
default as useSendControlMessage,
|
package/template/package.json
CHANGED
|
@@ -62,12 +62,14 @@
|
|
|
62
62
|
"electron-updater": "4.3.9",
|
|
63
63
|
"exponential-backoff": "3.1.0",
|
|
64
64
|
"graphql": "15.5.0",
|
|
65
|
+
"nanoid": "4.0.0",
|
|
65
66
|
"nosleep.js": "0.12.0",
|
|
66
67
|
"react": "16.13.1",
|
|
67
68
|
"react-dom": "16.13.1",
|
|
68
69
|
"react-is": "18.0.0",
|
|
69
70
|
"react-native": "0.63.3",
|
|
70
71
|
"react-native-agora": "3.4.2",
|
|
72
|
+
"react-native-get-random-values": "1.8.0",
|
|
71
73
|
"react-native-hyperlink": "0.0.19",
|
|
72
74
|
"react-native-inappbrowser-reborn": "3.5.1",
|
|
73
75
|
"react-native-keep-awake": "4.0.0",
|
|
@@ -16,18 +16,25 @@ import {createContext, SetStateAction} from 'react';
|
|
|
16
16
|
export interface ChatBubbleProps {
|
|
17
17
|
isLocal: boolean;
|
|
18
18
|
message: string;
|
|
19
|
-
|
|
19
|
+
createdTimestamp: string;
|
|
20
|
+
updatedTimestamp?: string;
|
|
20
21
|
uid: UidType;
|
|
22
|
+
msgId: string;
|
|
23
|
+
isDeleted: boolean;
|
|
21
24
|
render?: (
|
|
22
25
|
isLocal: boolean,
|
|
23
26
|
message: string,
|
|
24
|
-
|
|
27
|
+
createdTimestamp: string,
|
|
25
28
|
uid: UidType,
|
|
29
|
+
msgId: string,
|
|
30
|
+
isDeleted: boolean,
|
|
31
|
+
updatedTimestamp?: string,
|
|
26
32
|
) => JSX.Element;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
export interface messageStoreInterface {
|
|
30
|
-
|
|
36
|
+
createdTimestamp: string;
|
|
37
|
+
updatedTimestamp?: string;
|
|
31
38
|
uid: UidType;
|
|
32
39
|
msg: string;
|
|
33
40
|
}
|
|
@@ -21,28 +21,42 @@ import {useChatNotification} from '../chat-notification/useChatNotification';
|
|
|
21
21
|
import Toast from '../../../react-native-toast-message';
|
|
22
22
|
import {timeNow} from '../../rtm/utils';
|
|
23
23
|
import {useSidePanel} from '../../utils/useSidePanel';
|
|
24
|
+
import getUniqueID from '../../utils/getUniqueID';
|
|
25
|
+
|
|
26
|
+
enum ChatMessageActionEnum {
|
|
27
|
+
Create = 'Create_Chat_Message',
|
|
28
|
+
Update = 'Update_Chat_Message',
|
|
29
|
+
Delete = 'Delete_Chat_Message',
|
|
30
|
+
}
|
|
24
31
|
|
|
25
32
|
interface ChatMessagesProviderProps {
|
|
26
33
|
children: React.ReactNode;
|
|
27
34
|
}
|
|
28
35
|
interface messageInterface {
|
|
29
|
-
|
|
36
|
+
createdTimestamp: number;
|
|
37
|
+
updatedTimestamp?: number;
|
|
30
38
|
msg: string;
|
|
39
|
+
msgId: string;
|
|
40
|
+
isDeleted: boolean;
|
|
31
41
|
}
|
|
32
42
|
interface messageStoreInterface extends messageInterface {
|
|
33
43
|
uid: UidType;
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
interface ChatMessagesInterface {
|
|
37
|
-
messageStore: messageStoreInterface
|
|
38
|
-
privateMessageStore:
|
|
47
|
+
messageStore: messageStoreInterface[];
|
|
48
|
+
privateMessageStore: {[key: string]: messageStoreInterface[]};
|
|
39
49
|
sendChatMessage: (msg: string, toUid?: UidType) => void;
|
|
50
|
+
editChatMessage: (msgId: string, msg: string, toUid?: UidType) => void;
|
|
51
|
+
deleteChatMessage: (msgId: string, toUid?: UidType) => void;
|
|
40
52
|
}
|
|
41
53
|
|
|
42
54
|
const ChatMessagesContext = React.createContext<ChatMessagesInterface>({
|
|
43
55
|
messageStore: [],
|
|
44
56
|
privateMessageStore: {},
|
|
45
57
|
sendChatMessage: () => {},
|
|
58
|
+
editChatMessage: () => {},
|
|
59
|
+
deleteChatMessage: () => {},
|
|
46
60
|
});
|
|
47
61
|
|
|
48
62
|
const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
|
|
@@ -53,7 +67,9 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
|
|
|
53
67
|
const {setUnreadGroupMessageCount, setUnreadIndividualMessageCount} =
|
|
54
68
|
useChatNotification();
|
|
55
69
|
const [messageStore, setMessageStore] = useState<messageStoreInterface[]>([]);
|
|
56
|
-
const [privateMessageStore, setPrivateMessageStore] = useState
|
|
70
|
+
const [privateMessageStore, setPrivateMessageStore] = useState<{
|
|
71
|
+
[key: string]: messageStoreInterface[];
|
|
72
|
+
}>({});
|
|
57
73
|
|
|
58
74
|
const renderListRef = useRef({renderList: renderList});
|
|
59
75
|
const groupActiveRef = useRef<boolean>();
|
|
@@ -91,54 +107,168 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
|
|
|
91
107
|
});
|
|
92
108
|
};
|
|
93
109
|
CustomEvents.on(EventNames.PUBLIC_CHAT_MESSAGE, (data) => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
const messageData = JSON.parse(data.payload.value);
|
|
111
|
+
switch (data?.payload?.action) {
|
|
112
|
+
case ChatMessageActionEnum.Create:
|
|
113
|
+
showMessageNotification(messageData.msg, data.sender);
|
|
114
|
+
addMessageToStore(parseInt(data.sender), {
|
|
115
|
+
msg: messageData.msg,
|
|
116
|
+
createdTimestamp: messageData.createdTimestamp,
|
|
117
|
+
isDeleted: messageData.isDeleted,
|
|
118
|
+
msgId: messageData.msgId,
|
|
119
|
+
});
|
|
120
|
+
/**
|
|
121
|
+
* if chat group window is not active.
|
|
122
|
+
* then we will increment the unread count
|
|
123
|
+
*/
|
|
124
|
+
if (!groupActiveRef.current) {
|
|
125
|
+
setUnreadGroupMessageCount((prevState) => {
|
|
126
|
+
return prevState + 1;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
case ChatMessageActionEnum.Update:
|
|
131
|
+
setMessageStore((prevState) => {
|
|
132
|
+
const newState = prevState.map((item) => {
|
|
133
|
+
if (
|
|
134
|
+
item.msgId === messageData.msgId &&
|
|
135
|
+
item.uid === parseInt(data.sender)
|
|
136
|
+
) {
|
|
137
|
+
return {
|
|
138
|
+
...item,
|
|
139
|
+
msg: messageData.msg,
|
|
140
|
+
updatedTimestamp: messageData.updatedTimestamp,
|
|
141
|
+
};
|
|
142
|
+
} else {
|
|
143
|
+
return item;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return newState;
|
|
147
|
+
});
|
|
148
|
+
break;
|
|
149
|
+
case ChatMessageActionEnum.Delete:
|
|
150
|
+
setMessageStore((prevState) => {
|
|
151
|
+
const newState = prevState.map((item) => {
|
|
152
|
+
if (
|
|
153
|
+
item.msgId === messageData.msgId &&
|
|
154
|
+
item.uid === parseInt(data.sender)
|
|
155
|
+
) {
|
|
156
|
+
return {
|
|
157
|
+
...item,
|
|
158
|
+
isDeleted: true,
|
|
159
|
+
updatedTimestamp: messageData.updatedTimestamp,
|
|
160
|
+
};
|
|
161
|
+
} else {
|
|
162
|
+
return item;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return newState;
|
|
166
|
+
});
|
|
167
|
+
break;
|
|
168
|
+
default:
|
|
169
|
+
break;
|
|
107
170
|
}
|
|
108
171
|
});
|
|
109
172
|
CustomEvents.on(EventNames.PRIVATE_CHAT_MESSAGE, (data) => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
msg
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
173
|
+
const messageData = JSON.parse(data.payload.value);
|
|
174
|
+
|
|
175
|
+
switch (data?.payload?.action) {
|
|
176
|
+
case ChatMessageActionEnum.Create:
|
|
177
|
+
showMessageNotification(messageData.msg, data.sender);
|
|
178
|
+
addMessageToPrivateStore(
|
|
179
|
+
parseInt(data.sender),
|
|
180
|
+
{
|
|
181
|
+
msg: messageData.msg,
|
|
182
|
+
createdTimestamp: messageData.createdTimestamp,
|
|
183
|
+
msgId: messageData.msgId,
|
|
184
|
+
isDeleted: messageData.isDeleted,
|
|
185
|
+
},
|
|
186
|
+
false,
|
|
187
|
+
);
|
|
188
|
+
/**
|
|
189
|
+
* if user's private window is active.
|
|
190
|
+
* then we will not increment the unread count
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
if (!(individualActiveRef.current === parseInt(data.sender))) {
|
|
194
|
+
setUnreadIndividualMessageCount((prevState) => {
|
|
195
|
+
const prevCount =
|
|
196
|
+
prevState && prevState[parseInt(data.sender)]
|
|
197
|
+
? prevState[parseInt(data.sender)]
|
|
198
|
+
: 0;
|
|
199
|
+
return {
|
|
200
|
+
...prevState,
|
|
201
|
+
[parseInt(data.sender)]: prevCount + 1,
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case ChatMessageActionEnum.Update:
|
|
207
|
+
setPrivateMessageStore((prevState) => {
|
|
208
|
+
const privateChatOfUid = prevState[parseInt(data.sender)];
|
|
209
|
+
const updatedData = privateChatOfUid.map((item) => {
|
|
210
|
+
if (
|
|
211
|
+
item.msgId === messageData.msgId &&
|
|
212
|
+
item.uid === parseInt(data.sender)
|
|
213
|
+
) {
|
|
214
|
+
return {
|
|
215
|
+
...item,
|
|
216
|
+
msg: messageData.msg,
|
|
217
|
+
updatedTimestamp: messageData.updatedTimestamp,
|
|
218
|
+
};
|
|
219
|
+
} else {
|
|
220
|
+
return item;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const newState = {
|
|
224
|
+
...prevState,
|
|
225
|
+
[parseInt(data.sender)]: updatedData,
|
|
226
|
+
};
|
|
227
|
+
return newState;
|
|
228
|
+
});
|
|
229
|
+
break;
|
|
230
|
+
case ChatMessageActionEnum.Delete:
|
|
231
|
+
setPrivateMessageStore((prevState) => {
|
|
232
|
+
const privateChatOfUid = prevState[parseInt(data.sender)];
|
|
233
|
+
const updatedData = privateChatOfUid.map((item) => {
|
|
234
|
+
if (
|
|
235
|
+
item.msgId === messageData.msgId &&
|
|
236
|
+
item.uid === parseInt(data.sender)
|
|
237
|
+
) {
|
|
238
|
+
return {
|
|
239
|
+
...item,
|
|
240
|
+
isDeleted: true,
|
|
241
|
+
updatedTimestamp: messageData.updatedTimestamp,
|
|
242
|
+
};
|
|
243
|
+
} else {
|
|
244
|
+
return item;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
const newState = {
|
|
248
|
+
...prevState,
|
|
249
|
+
[parseInt(data.sender)]: updatedData,
|
|
250
|
+
};
|
|
251
|
+
return newState;
|
|
252
|
+
});
|
|
253
|
+
break;
|
|
254
|
+
default:
|
|
255
|
+
break;
|
|
135
256
|
}
|
|
136
257
|
});
|
|
137
258
|
}, []);
|
|
138
259
|
|
|
139
260
|
const addMessageToStore = (uid: UidType, body: messageInterface) => {
|
|
140
261
|
setMessageStore((m: messageStoreInterface[]) => {
|
|
141
|
-
return [
|
|
262
|
+
return [
|
|
263
|
+
...m,
|
|
264
|
+
{
|
|
265
|
+
createdTimestamp: body.createdTimestamp,
|
|
266
|
+
uid,
|
|
267
|
+
msg: body.msg,
|
|
268
|
+
msgId: body.msgId,
|
|
269
|
+
isDeleted: body.isDeleted,
|
|
270
|
+
},
|
|
271
|
+
];
|
|
142
272
|
});
|
|
143
273
|
};
|
|
144
274
|
|
|
@@ -147,16 +277,30 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
|
|
|
147
277
|
body: messageInterface,
|
|
148
278
|
local: boolean,
|
|
149
279
|
) => {
|
|
150
|
-
setPrivateMessageStore((state
|
|
280
|
+
setPrivateMessageStore((state) => {
|
|
151
281
|
let newState = {...state};
|
|
152
282
|
newState[uid] !== undefined
|
|
153
283
|
? (newState[uid] = [
|
|
154
284
|
...newState[uid],
|
|
155
|
-
{
|
|
285
|
+
{
|
|
286
|
+
createdTimestamp: body.createdTimestamp,
|
|
287
|
+
uid: local ? localUid : uid,
|
|
288
|
+
msg: body.msg,
|
|
289
|
+
msgId: body.msgId,
|
|
290
|
+
isDeleted: body.isDeleted,
|
|
291
|
+
},
|
|
156
292
|
])
|
|
157
293
|
: (newState = {
|
|
158
294
|
...newState,
|
|
159
|
-
[uid]: [
|
|
295
|
+
[uid]: [
|
|
296
|
+
{
|
|
297
|
+
createdTimestamp: body.createdTimestamp,
|
|
298
|
+
uid: local ? localUid : uid,
|
|
299
|
+
msg: body.msg,
|
|
300
|
+
msgId: body.msgId,
|
|
301
|
+
isDeleted: body.isDeleted,
|
|
302
|
+
},
|
|
303
|
+
],
|
|
160
304
|
});
|
|
161
305
|
return {...newState};
|
|
162
306
|
});
|
|
@@ -165,29 +309,148 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
|
|
|
165
309
|
const sendChatMessage = (msg: string, toUid?: UidType) => {
|
|
166
310
|
if (typeof msg == 'string' && msg.trim() === '') return;
|
|
167
311
|
if (toUid) {
|
|
312
|
+
const messageData = {
|
|
313
|
+
msg,
|
|
314
|
+
createdTimestamp: timeNow(),
|
|
315
|
+
msgId: getUniqueID(),
|
|
316
|
+
isDeleted: false,
|
|
317
|
+
};
|
|
168
318
|
CustomEvents.send(
|
|
169
319
|
EventNames.PRIVATE_CHAT_MESSAGE,
|
|
170
320
|
{
|
|
171
|
-
value:
|
|
321
|
+
value: JSON.stringify(messageData),
|
|
322
|
+
action: ChatMessageActionEnum.Create,
|
|
172
323
|
},
|
|
173
324
|
toUid,
|
|
174
325
|
);
|
|
175
|
-
addMessageToPrivateStore(
|
|
176
|
-
toUid,
|
|
177
|
-
{
|
|
178
|
-
msg: msg,
|
|
179
|
-
ts: timeNow(),
|
|
180
|
-
},
|
|
181
|
-
true,
|
|
182
|
-
);
|
|
326
|
+
addMessageToPrivateStore(toUid, messageData, true);
|
|
183
327
|
} else {
|
|
328
|
+
const messageData = {
|
|
329
|
+
msg,
|
|
330
|
+
msgId: getUniqueID(),
|
|
331
|
+
isDeleted: false,
|
|
332
|
+
createdTimestamp: timeNow(),
|
|
333
|
+
};
|
|
184
334
|
CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
|
|
185
|
-
value:
|
|
186
|
-
|
|
187
|
-
addMessageToStore(localUid, {
|
|
188
|
-
msg: msg,
|
|
189
|
-
ts: timeNow(),
|
|
335
|
+
value: JSON.stringify(messageData),
|
|
336
|
+
action: ChatMessageActionEnum.Create,
|
|
190
337
|
});
|
|
338
|
+
addMessageToStore(localUid, messageData);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const editChatMessage = (msgId: string, msg: string, toUid?: UidType) => {
|
|
343
|
+
if (typeof msg == 'string' && msg.trim() === '') return;
|
|
344
|
+
if (toUid) {
|
|
345
|
+
const checkData = privateMessageStore[toUid].filter(
|
|
346
|
+
(item) => item.msgId === msgId && item.uid === localUid,
|
|
347
|
+
);
|
|
348
|
+
if (checkData && checkData.length) {
|
|
349
|
+
const editMsgData = {msg, updatedTimestamp: timeNow()};
|
|
350
|
+
CustomEvents.send(
|
|
351
|
+
EventNames.PRIVATE_CHAT_MESSAGE,
|
|
352
|
+
{
|
|
353
|
+
value: JSON.stringify({msgId, ...editMsgData}),
|
|
354
|
+
action: ChatMessageActionEnum.Update,
|
|
355
|
+
},
|
|
356
|
+
toUid,
|
|
357
|
+
);
|
|
358
|
+
setPrivateMessageStore((prevState) => {
|
|
359
|
+
const privateChatOfUid = prevState[toUid];
|
|
360
|
+
const updatedData = privateChatOfUid.map((item) => {
|
|
361
|
+
if (item.msgId === msgId) {
|
|
362
|
+
return {...item, ...editMsgData};
|
|
363
|
+
} else {
|
|
364
|
+
return item;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
const newState = {...prevState, [toUid]: updatedData};
|
|
368
|
+
return newState;
|
|
369
|
+
});
|
|
370
|
+
} else {
|
|
371
|
+
console.log("You don't have permission to edit");
|
|
372
|
+
}
|
|
373
|
+
} else {
|
|
374
|
+
//check if user has permission to edit
|
|
375
|
+
const checkData = messageStore.filter(
|
|
376
|
+
(item) => item.msgId === msgId && item.uid === localUid,
|
|
377
|
+
);
|
|
378
|
+
if (checkData && checkData.length) {
|
|
379
|
+
const editMsgData = {msg, updatedTimestamp: timeNow()};
|
|
380
|
+
CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
|
|
381
|
+
value: JSON.stringify({msgId, ...editMsgData}),
|
|
382
|
+
action: ChatMessageActionEnum.Update,
|
|
383
|
+
});
|
|
384
|
+
setMessageStore((prevState) => {
|
|
385
|
+
const newState = prevState.map((item) => {
|
|
386
|
+
if (item.msgId === msgId) {
|
|
387
|
+
return {...item, ...editMsgData};
|
|
388
|
+
} else {
|
|
389
|
+
return item;
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
return newState;
|
|
393
|
+
});
|
|
394
|
+
} else {
|
|
395
|
+
console.log("You don't have permission to edit");
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const deleteChatMessage = (msgId: string, toUid?: UidType) => {
|
|
401
|
+
if (toUid) {
|
|
402
|
+
const checkData = privateMessageStore[toUid].filter(
|
|
403
|
+
(item) => item.msgId === msgId && item.uid === localUid,
|
|
404
|
+
);
|
|
405
|
+
if (checkData && checkData.length) {
|
|
406
|
+
const deleteMsgData = {updatedTimestamp: timeNow()};
|
|
407
|
+
CustomEvents.send(
|
|
408
|
+
EventNames.PRIVATE_CHAT_MESSAGE,
|
|
409
|
+
{
|
|
410
|
+
value: JSON.stringify({msgId, ...deleteMsgData}),
|
|
411
|
+
action: ChatMessageActionEnum.Delete,
|
|
412
|
+
},
|
|
413
|
+
toUid,
|
|
414
|
+
);
|
|
415
|
+
setPrivateMessageStore((prevState) => {
|
|
416
|
+
const privateChatOfUid = prevState[toUid];
|
|
417
|
+
const updatedData = privateChatOfUid.map((item) => {
|
|
418
|
+
if (item.msgId === msgId) {
|
|
419
|
+
return {...item, isDeleted: true, ...deleteMsgData};
|
|
420
|
+
} else {
|
|
421
|
+
return item;
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
const newState = {...prevState, [toUid]: updatedData};
|
|
425
|
+
return newState;
|
|
426
|
+
});
|
|
427
|
+
} else {
|
|
428
|
+
console.log("You don't have permission to delete");
|
|
429
|
+
}
|
|
430
|
+
} else {
|
|
431
|
+
//check if user has permission to delete
|
|
432
|
+
const checkData = messageStore.filter(
|
|
433
|
+
(item) => item.msgId === msgId && item.uid === localUid,
|
|
434
|
+
);
|
|
435
|
+
if (checkData && checkData.length) {
|
|
436
|
+
const deleteMsgData = {updatedTimestamp: timeNow()};
|
|
437
|
+
CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
|
|
438
|
+
value: JSON.stringify({msgId, ...deleteMsgData}),
|
|
439
|
+
action: ChatMessageActionEnum.Delete,
|
|
440
|
+
});
|
|
441
|
+
setMessageStore((prevState) => {
|
|
442
|
+
const newState = prevState.map((item) => {
|
|
443
|
+
if (item.msgId === msgId) {
|
|
444
|
+
return {...item, isDeleted: true, ...deleteMsgData};
|
|
445
|
+
} else {
|
|
446
|
+
return item;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
return newState;
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
console.log("You don't have permission to delete");
|
|
453
|
+
}
|
|
191
454
|
}
|
|
192
455
|
};
|
|
193
456
|
|
|
@@ -197,6 +460,8 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
|
|
|
197
460
|
messageStore,
|
|
198
461
|
privateMessageStore,
|
|
199
462
|
sendChatMessage,
|
|
463
|
+
editChatMessage,
|
|
464
|
+
deleteChatMessage,
|
|
200
465
|
}}>
|
|
201
466
|
{props.children}
|
|
202
467
|
</ChatMessagesContext.Provider>
|
|
@@ -21,11 +21,19 @@ import useUserList from '../utils/useUserList';
|
|
|
21
21
|
const ChatBubble = (props: ChatBubbleProps) => {
|
|
22
22
|
const {renderList} = useUserList();
|
|
23
23
|
const {primaryColor} = useContext(ColorContext);
|
|
24
|
-
let {
|
|
24
|
+
let {
|
|
25
|
+
isLocal,
|
|
26
|
+
message,
|
|
27
|
+
createdTimestamp,
|
|
28
|
+
uid,
|
|
29
|
+
isDeleted,
|
|
30
|
+
msgId,
|
|
31
|
+
updatedTimestamp,
|
|
32
|
+
} = props;
|
|
25
33
|
let time =
|
|
26
|
-
new Date(parseInt(
|
|
34
|
+
new Date(parseInt(createdTimestamp)).getHours() +
|
|
27
35
|
':' +
|
|
28
|
-
new Date(parseInt(
|
|
36
|
+
new Date(parseInt(createdTimestamp)).getMinutes();
|
|
29
37
|
const handleUrl = (url: string) => {
|
|
30
38
|
if (isWeb) {
|
|
31
39
|
window.open(url, '_blank');
|
|
@@ -37,7 +45,15 @@ const ChatBubble = (props: ChatBubbleProps) => {
|
|
|
37
45
|
//const remoteUserDefaultLabel = useString('remoteUserDefaultLabel')();
|
|
38
46
|
const remoteUserDefaultLabel = 'User';
|
|
39
47
|
return props?.render ? (
|
|
40
|
-
props.render(
|
|
48
|
+
props.render(
|
|
49
|
+
isLocal,
|
|
50
|
+
message,
|
|
51
|
+
createdTimestamp,
|
|
52
|
+
uid,
|
|
53
|
+
msgId,
|
|
54
|
+
isDeleted,
|
|
55
|
+
updatedTimestamp,
|
|
56
|
+
)
|
|
41
57
|
) : (
|
|
42
58
|
<View>
|
|
43
59
|
<View style={isLocal ? style.chatSenderViewLocal : style.chatSenderView}>
|
|
@@ -129,9 +129,12 @@ const ChatContainer = (props?: {
|
|
|
129
129
|
<ChatBubbleComponent
|
|
130
130
|
isLocal={localUid === message.uid}
|
|
131
131
|
message={message.msg}
|
|
132
|
-
|
|
132
|
+
createdTimestamp={message.createdTimestamp}
|
|
133
|
+
updatedTimestamp={message.updatedTimestamp}
|
|
133
134
|
uid={message.uid}
|
|
134
135
|
key={message.ts}
|
|
136
|
+
msgId={message.msgId}
|
|
137
|
+
isDeleted={message.isDeleted}
|
|
135
138
|
/>
|
|
136
139
|
</>
|
|
137
140
|
))
|
|
@@ -140,9 +143,12 @@ const ChatContainer = (props?: {
|
|
|
140
143
|
<ChatBubbleComponent
|
|
141
144
|
isLocal={localUid === message.uid}
|
|
142
145
|
message={message.msg}
|
|
143
|
-
|
|
146
|
+
createdTimestamp={message.createdTimestamp}
|
|
147
|
+
updatedTimestamp={message.updatedTimestamp}
|
|
144
148
|
uid={message.uid}
|
|
145
149
|
key={message.ts}
|
|
150
|
+
msgId={message.msgId}
|
|
151
|
+
isDeleted={message.isDeleted}
|
|
146
152
|
/>
|
|
147
153
|
))
|
|
148
154
|
) : (
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
********************************************
|
|
3
|
+
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
+
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
+
(the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
+
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
+
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
+
any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
|
|
9
|
+
information visit https://appbuilder.agora.io.
|
|
10
|
+
*********************************************
|
|
11
|
+
*/
|
|
12
|
+
import {UidType} from '../../agora-rn-uikit';
|
|
13
|
+
import {useChatMessages} from '../components/chat-messages/useChatMessages';
|
|
14
|
+
import {MESSAGE_TYPE} from './useSendMessage';
|
|
15
|
+
|
|
16
|
+
function useDeleteMessage() {
|
|
17
|
+
const {deleteChatMessage} = useChatMessages();
|
|
18
|
+
return (type: MESSAGE_TYPE, msgId: string, uid?: UidType) => {
|
|
19
|
+
switch (type) {
|
|
20
|
+
case MESSAGE_TYPE.group:
|
|
21
|
+
deleteChatMessage(msgId);
|
|
22
|
+
break;
|
|
23
|
+
case MESSAGE_TYPE.private:
|
|
24
|
+
if (uid) {
|
|
25
|
+
deleteChatMessage(msgId, uid);
|
|
26
|
+
} else {
|
|
27
|
+
console.error('To delete the private message, UID should be passed');
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
default:
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default useDeleteMessage;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
********************************************
|
|
3
|
+
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
+
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
+
(the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
+
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
+
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
+
any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
|
|
9
|
+
information visit https://appbuilder.agora.io.
|
|
10
|
+
*********************************************
|
|
11
|
+
*/
|
|
12
|
+
import {UidType} from '../../agora-rn-uikit';
|
|
13
|
+
import {useChatMessages} from '../components/chat-messages/useChatMessages';
|
|
14
|
+
import {MESSAGE_TYPE} from './useSendMessage';
|
|
15
|
+
|
|
16
|
+
function useEditMessage() {
|
|
17
|
+
const {editChatMessage} = useChatMessages();
|
|
18
|
+
return (
|
|
19
|
+
type: MESSAGE_TYPE,
|
|
20
|
+
msgId: string,
|
|
21
|
+
message: string,
|
|
22
|
+
uid?: UidType,
|
|
23
|
+
) => {
|
|
24
|
+
switch (type) {
|
|
25
|
+
case MESSAGE_TYPE.group:
|
|
26
|
+
editChatMessage(msgId, message);
|
|
27
|
+
break;
|
|
28
|
+
case MESSAGE_TYPE.private:
|
|
29
|
+
if (uid) {
|
|
30
|
+
editChatMessage(msgId, message, uid);
|
|
31
|
+
} else {
|
|
32
|
+
console.error('To edit the private message, UID should be passed');
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default useEditMessage;
|
|
@@ -9,24 +9,23 @@
|
|
|
9
9
|
information visit https://appbuilder.agora.io.
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
|
-
import {useContext} from 'react';
|
|
13
|
-
import ChatContext from '../components/ChatContext';
|
|
14
12
|
import {UidType} from '../../agora-rn-uikit';
|
|
13
|
+
import {useChatMessages} from '../components/chat-messages/useChatMessages';
|
|
15
14
|
|
|
16
15
|
export enum MESSAGE_TYPE {
|
|
17
16
|
group,
|
|
18
17
|
private,
|
|
19
18
|
}
|
|
20
19
|
function useSendMessage() {
|
|
21
|
-
const {
|
|
20
|
+
const {sendChatMessage} = useChatMessages();
|
|
22
21
|
return (type: MESSAGE_TYPE, message: string, uid?: UidType) => {
|
|
23
22
|
switch (type) {
|
|
24
23
|
case MESSAGE_TYPE.group:
|
|
25
|
-
|
|
24
|
+
sendChatMessage(message);
|
|
26
25
|
break;
|
|
27
26
|
case MESSAGE_TYPE.private:
|
|
28
27
|
if (uid) {
|
|
29
|
-
|
|
28
|
+
sendChatMessage(message, uid);
|
|
30
29
|
} else {
|
|
31
30
|
console.error('To send the private message, UID should be passed');
|
|
32
31
|
}
|