@webinex/chatify 1.0.0-rc3 → 1.0.2-rc3

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 (98) hide show
  1. package/dist/esm/index.js +1 -1
  2. package/dist/esm/index.js.map +1 -1
  3. package/dist/esm/types/core/action.d.ts +10 -4
  4. package/dist/esm/types/core/state.d.ts +2 -1
  5. package/dist/esm/types/core/useGetAccountsQuery.d.ts +3 -1
  6. package/dist/esm/types/core/useGetChatListQuery.d.ts +3 -1
  7. package/dist/esm/types/core/useGetChatQuery.d.ts +3 -1
  8. package/dist/esm/types/ui/Icon.d.ts +8 -8
  9. package/dist/index.d.ts +21 -14
  10. package/package.json +92 -92
  11. package/src/ChatifyContext.tsx +41 -41
  12. package/src/core/action.tsx +421 -405
  13. package/src/core/client.ts +143 -143
  14. package/src/core/index.ts +17 -17
  15. package/src/core/models.tsx +82 -82
  16. package/src/core/reducer.tsx +87 -87
  17. package/src/core/state.ts +93 -92
  18. package/src/core/useAddChatMutation.tsx +22 -22
  19. package/src/core/useAddMemberMutation.tsx +25 -25
  20. package/src/core/useFetchNextMutation.tsx +28 -28
  21. package/src/core/useGetAccountsQuery.tsx +30 -33
  22. package/src/core/useGetChatListQuery.tsx +30 -33
  23. package/src/core/useGetChatQuery.tsx +31 -34
  24. package/src/core/useGetMessagesQuery.tsx +35 -35
  25. package/src/core/useReadMonitor.tsx +32 -32
  26. package/src/core/useRemoveMemberMutation.tsx +23 -23
  27. package/src/core/useSendMutation.tsx +24 -24
  28. package/src/core/useSignalRMonitor.tsx +66 -66
  29. package/src/core/useUpdateChatNameMutation.tsx +23 -23
  30. package/src/index.ts +3 -3
  31. package/src/styles/aside.scss +94 -94
  32. package/src/styles/chat.scss +222 -222
  33. package/src/styles/index.scss +79 -79
  34. package/src/styles/keyframes.scss +14 -14
  35. package/src/styles/mixins.scss +20 -20
  36. package/src/styles/settings.scss +5 -5
  37. package/src/styles/variables.scss +10 -10
  38. package/src/ui/AddChatButton.tsx +15 -15
  39. package/src/ui/Avatar.tsx +18 -18
  40. package/src/ui/ChatList/ChatList.tsx +42 -42
  41. package/src/ui/ChatList/ChatListItemBox.tsx +22 -22
  42. package/src/ui/ChatList/ChatListItemLastMessage.tsx +13 -13
  43. package/src/ui/ChatList/ChatListItemLastMessageAuthor.tsx +20 -20
  44. package/src/ui/ChatList/ChatListItemLastMessageContent.tsx +21 -21
  45. package/src/ui/ChatList/ChatListItemName.tsx +13 -13
  46. package/src/ui/ChatList/ChatListItemUnreadCount.tsx +12 -12
  47. package/src/ui/ChatList/index.ts +7 -7
  48. package/src/ui/ChatName.tsx +10 -10
  49. package/src/ui/ChatPanel/ChatBody.tsx +44 -44
  50. package/src/ui/ChatPanel/ChatHeader.tsx +33 -33
  51. package/src/ui/ChatPanel/ChatHeaderMembers.tsx +26 -26
  52. package/src/ui/ChatPanel/ChatHeaderName.tsx +67 -67
  53. package/src/ui/ChatPanel/ChatMembersButton.tsx +21 -21
  54. package/src/ui/ChatPanel/ChatMembersPanel.tsx +117 -117
  55. package/src/ui/ChatPanel/ChatPanel.tsx +27 -27
  56. package/src/ui/ChatPanel/index.ts +6 -6
  57. package/src/ui/Chatify.tsx +148 -148
  58. package/src/ui/CreateChatPanel/CreateChatForm.tsx +36 -36
  59. package/src/ui/CreateChatPanel/CreateChatMemberInput.tsx +66 -66
  60. package/src/ui/CreateChatPanel/CreateChatNameInput.tsx +25 -25
  61. package/src/ui/CreateChatPanel/CreateChatPanel.tsx +33 -33
  62. package/src/ui/CreateChatPanel/index.ts +4 -4
  63. package/src/ui/Icon.tsx +33 -33
  64. package/src/ui/InputBox/InputBox.tsx +38 -38
  65. package/src/ui/InputBox/InputFilesBox.tsx +9 -9
  66. package/src/ui/InputBox/InputSubmitButtonBox.tsx +17 -17
  67. package/src/ui/InputBox/InputTextBox.tsx +50 -50
  68. package/src/ui/InputBox/index.ts +4 -4
  69. package/src/ui/Layout/Aside.tsx +10 -10
  70. package/src/ui/Layout/Body.tsx +10 -10
  71. package/src/ui/Layout/Footer.tsx +3 -3
  72. package/src/ui/Layout/Header.tsx +10 -10
  73. package/src/ui/Layout/Main.tsx +15 -15
  74. package/src/ui/Layout/index.ts +5 -5
  75. package/src/ui/Message/MessageAuthor.tsx +13 -13
  76. package/src/ui/Message/MessageBox.tsx +20 -20
  77. package/src/ui/Message/MessageContent.tsx +13 -13
  78. package/src/ui/Message/MessageInfoBox.tsx +25 -25
  79. package/src/ui/Message/MessageRow.tsx +24 -24
  80. package/src/ui/Message/MessageText.tsx +7 -7
  81. package/src/ui/Message/index.ts +6 -6
  82. package/src/ui/MessageReadObserver.tsx +45 -45
  83. package/src/ui/MessageSkeleton.tsx +19 -19
  84. package/src/ui/Next.tsx +48 -48
  85. package/src/ui/SendingMessage/SendingMessageBox.tsx +16 -16
  86. package/src/ui/SendingMessage/SendingMessageContent.tsx +13 -13
  87. package/src/ui/SendingMessage/SendingMessageInfoBox.tsx +13 -13
  88. package/src/ui/SendingMessage/SendingMessageText.tsx +7 -7
  89. package/src/ui/SendingMessage/index.ts +4 -4
  90. package/src/ui/SystemMessage/SystemMessageBox.tsx +20 -20
  91. package/src/ui/SystemMessage/SystemMessageRow.tsx +43 -43
  92. package/src/ui/SystemMessage/index.ts +2 -2
  93. package/src/ui/customize.tsx +45 -45
  94. package/src/ui/index.ts +11 -11
  95. package/src/ui/localizer.tsx +80 -80
  96. package/src/util/index.ts +2 -2
  97. package/src/util/uniqBy.tsx +17 -17
  98. package/src/util/uniqId.tsx +3 -3
@@ -1,405 +1,421 @@
1
- import type { State } from './state';
2
- import { Account, Chat, ChatListItem, Message, ReadEvent, File } from './models';
3
-
4
- export const ACTIONS = {
5
- update: (state: State, { mutation }: { mutation: (state: State) => State }) => {
6
- mutation(state);
7
- },
8
-
9
- messages_fetch: (state: State, { chatId }: { chatId: string }) => {
10
- state.query.messages[chatId] = {
11
- ...state.query.messages[chatId],
12
- uninitialized: false,
13
- isFetching: true,
14
- };
15
- },
16
-
17
- messages_fulfilled: (
18
- state: State,
19
- { chatId, messages, hasMore }: { chatId: string; messages: Message[]; hasMore: boolean },
20
- ) => {
21
- const qState = state.query.messages[chatId];
22
-
23
- qState.error = undefined;
24
- qState.isFetching = false;
25
- qState.data = messages.map((x) => ({ type: 'message', ...x }));
26
-
27
- if (hasMore) {
28
- qState.data!.push({ type: 'next' });
29
- }
30
- },
31
-
32
- messages_rejected: (state: State, { chatId, error }: { chatId: string; error: any }) => {
33
- const qState = state.query.messages[chatId];
34
- qState.error = error;
35
- qState.isFetching = false;
36
- },
37
-
38
- fetchNext_fetch: (state: State, { chatId }: { chatId: string }) => {
39
- state.mutation.fetchNext = { isFetching: true };
40
- },
41
-
42
- fetchNext_fulfilled: (
43
- state: State,
44
- { chatId, messages, hasMore }: { chatId: string; messages: Message[]; hasMore: boolean },
45
- ) => {
46
- state.mutation.fetchNext = { isFetching: false, error: undefined };
47
- state.query.messages[chatId].data = state.query.messages[chatId].data!.filter((x) => x.type !== 'next');
48
- state.query.messages[chatId].data!.push(...messages.map((x) => ({ type: 'message' as const, ...x })));
49
-
50
- if (hasMore) state.query.messages[chatId].data!.push({ type: 'next' });
51
- },
52
-
53
- fetchNext_rejected: (state: State, { chatId, error }: { chatId: string; error: any }) => {
54
- state.mutation.fetchNext = { isFetching: false, error };
55
- },
56
-
57
- chatList_fetch: (state: State) => {
58
- state.query.chatList.isFetching = true;
59
- state.query.chatList.uninitialized = false;
60
- },
61
-
62
- chatList_fulfilled: (state: State, { chats }: { chats: ChatListItem[] }) => {
63
- chats = chats.sort((a, b) => -a.message.id.substring(47).localeCompare(b.message.id.substring(47)));
64
-
65
- state.query.chatList.isFetching = false;
66
- state.query.chatList.error = undefined;
67
- state.query.chatList.data = chats;
68
-
69
- if (state.ui.chatId === undefined && chats.length > 0) {
70
- state.ui.view = 'chat';
71
- state.ui.chatId = chats[0].id;
72
- }
73
- },
74
-
75
- chatList_rejected: (state: State, { error }: { error: any }) => {
76
- state.query.chatList.isFetching = false;
77
- state.query.chatList.error = error;
78
- },
79
-
80
- removeMember_fetch: (state: State) => {
81
- state.mutation.removeMember = { isFetching: true };
82
- },
83
-
84
- removeMember_fulfilled: (state: State) => {
85
- state.mutation.removeMember = { isFetching: false, error: undefined };
86
- },
87
-
88
- removeMember_rejected: (state: State, { error }: { error: any }) => {
89
- state.mutation.removeMember = { isFetching: false, error };
90
- },
91
-
92
- addMember_fetch: (state: State) => {
93
- state.mutation.addMember = { isFetching: true };
94
- },
95
-
96
- addMember_fulfilled: (state: State) => {
97
- state.mutation.addMember = { isFetching: false, error: undefined };
98
- },
99
-
100
- addMember_rejected: (state: State, { error }: { error: any }) => {
101
- state.mutation.addMember = { isFetching: false, error };
102
- },
103
-
104
- updateChatName_fetch: (state: State) => {
105
- state.mutation.updateChatName = { isFetching: true };
106
- },
107
-
108
- updateChatName_fulfilled: (state: State) => {
109
- state.mutation.updateChatName = { isFetching: false, error: undefined };
110
- },
111
-
112
- updateChatName_rejected: (state: State, { error }: { error: any }) => {
113
- state.mutation.updateChatName = { isFetching: false, error };
114
- },
115
-
116
- addChat_fetch: (state: State) => {
117
- state.mutation.addChat = { isFetching: true };
118
- },
119
-
120
- addChat_fulfilled: (state: State) => {
121
- state.mutation.addChat = { isFetching: false, error: undefined };
122
- },
123
-
124
- addChat_rejected: (state: State, { error }: { error: any }) => {
125
- state.mutation.addChat = { isFetching: false, error };
126
- },
127
-
128
- accounts_fetch: (state: State) => {
129
- state.query.accounts = { isFetching: true, uninitialized: false };
130
- },
131
-
132
- accounts_fulfilled: (state: State, { accounts }: { accounts: Account[] }) => {
133
- state.query.accounts.data = accounts;
134
- state.query.accounts.isFetching = false;
135
- state.query.accounts.error = undefined;
136
- },
137
-
138
- accounts_rejected: (state: State, { error }: { error: any }) => {
139
- state.query.accounts.isFetching = false;
140
- state.query.accounts.error = error;
141
- },
142
-
143
- chat_open: (state: State, { chatId }: { chatId: string }) => {
144
- state.ui.chatId = chatId;
145
- state.ui.view = 'chat';
146
- },
147
-
148
- new_chat_open: (state: State) => {
149
- state.ui.chatId = undefined;
150
- state.ui.view = 'new-chat';
151
- },
152
-
153
- toggle_members_view: (state: State) => {
154
- state.ui.showMembers = !state.ui.showMembers;
155
- },
156
-
157
- message_received: (
158
- state: State,
159
- { message, requestId, me }: { message: Message; requestId: string; me: string },
160
- ) => {
161
- const messagesState = state.query.messages[message.chatId];
162
-
163
- if (messagesState?.data) {
164
- messagesState.data.unshift({ type: 'message', ...message });
165
- messagesState.data = messagesState.data.filter(
166
- (x) => x.type !== 'sending' || x.requestId !== requestId,
167
- );
168
- }
169
-
170
- const chatListItemState = state.query.chatList?.data?.find((x) => x.id === message.chatId);
171
-
172
- if (chatListItemState) {
173
- chatListItemState.message = message;
174
- }
175
-
176
- if (chatListItemState && message.sentBy.id !== me) {
177
- chatListItemState.totalUnreadCount++;
178
- }
179
-
180
- if (chatListItemState && message.sentBy.id === me) {
181
- chatListItemState.lastReadMessageId = message.id;
182
- chatListItemState.totalUnreadCount = 0;
183
- }
184
- },
185
-
186
- chat_created: (state: State, { chat }: { chat: ChatListItem; requestId?: string }) => {
187
- state.query.chatList?.data?.unshift(chat);
188
- },
189
-
190
- read: (state: State, { id, timestamp }: { id: string; timestamp: number }) => {
191
- const queuedSameChat = state.queue.read.queued.filter((x) => x.substring(0, 36) === id.substring(0, 36));
192
-
193
- if (queuedSameChat.some((x) => x.localeCompare(id) >= 0)) {
194
- return;
195
- }
196
-
197
- state.queue.read.queued.filter((x) => queuedSameChat.includes(x));
198
- state.queue.read.queued.push(id);
199
- state.queue.read.timestamp = timestamp;
200
- },
201
-
202
- read_send: (state: State, { id }: { id: string }) => {
203
- state.queue.read.queued = state.queue.read.queued.filter((x) => x !== id);
204
- state.queue.read.processing.push(id);
205
- },
206
-
207
- read_reject: (state: State, { id, timestamp }: { id: string; timestamp: number }) => {
208
- state.queue.read.queued.push(id);
209
- state.queue.read.processing = state.queue.read.processing.filter((x) => x !== id);
210
- state.queue.read.timestamp = timestamp;
211
- },
212
-
213
- read_received: (state: State, { events }: { events: ReadEvent[] }) => {
214
- state.queue.read.processing = state.queue.read.processing.filter((item) => {
215
- const event = events.find((x) => x.chatId === item.substring(0, 36));
216
- return !event || event.newLastReadMessageId.localeCompare(item) >= 0;
217
- });
218
-
219
- for (const event of events) {
220
- state.queue.read.processing = state.queue.read.processing.filter(
221
- (x) => x.substring(0, 36) !== event.chatId || x.localeCompare(event.newLastReadMessageId) > 0,
222
- );
223
- const chatListItem = state.query.chatList.data?.find((x) => x.id === event.chatId);
224
-
225
- if (chatListItem) {
226
- chatListItem.lastReadMessageId = event.newLastReadMessageId;
227
- chatListItem.totalUnreadCount = chatListItem.totalUnreadCount - event.readCount;
228
- }
229
- }
230
- },
231
-
232
- member_added: (
233
- state: State,
234
- {
235
- chatId,
236
- chatName,
237
- account,
238
- me,
239
- message,
240
- withHistory,
241
- }: {
242
- chatId: string;
243
- chatName: string;
244
- account: Account;
245
- me: string;
246
- message: Message;
247
- withHistory: boolean;
248
- },
249
- ) => {
250
- const { chats, messages, chatList } = state.query;
251
- chats[chatId]?.data?.members.push(account);
252
- const chatListItem = chatList?.data?.find((x) => x.id === chatId);
253
-
254
- if (account.id !== me && chatListItem != null) {
255
- chatListItem.message = message;
256
- chatListItem.totalUnreadCount++;
257
- }
258
-
259
- messages[chatId]?.data?.unshift({ type: 'message', ...message });
260
-
261
- if (account.id === me && chatList.data !== undefined && !chatListItem) {
262
- chatList.data.unshift({
263
- id: chatId,
264
- name: chatName,
265
- message,
266
- totalUnreadCount: 1,
267
- active: true,
268
- lastReadMessageId: null,
269
- });
270
- }
271
-
272
- if (account.id === me && chatListItem) {
273
- chatListItem.active = true;
274
- chatListItem.message = message;
275
- chatListItem.totalUnreadCount++;
276
- }
277
-
278
- return state;
279
- },
280
-
281
- member_removed: (
282
- state: State,
283
- {
284
- chatId,
285
- accountId,
286
- deleteHistory,
287
- me,
288
- message,
289
- }: { chatId: string; accountId: string; deleteHistory: boolean; me: string; message: Message },
290
- ) => {
291
- const { chats, chatList } = state.query;
292
- const chat = chats[chatId];
293
-
294
- if (chat?.data) {
295
- chat.data.members = chat.data.members.filter((x) => x.id !== accountId);
296
- }
297
-
298
- if (accountId === me && state.query.chats[chatId].data) {
299
- delete state.query.chats[chatId];
300
- }
301
-
302
- if (accountId === me && deleteHistory && chatList?.data) {
303
- chatList.data = chatList.data.filter((x) => x.id !== chatId);
304
-
305
- if (state.ui.chatId === chatId) {
306
- state.ui.chatId = chatList.data.at(0)?.id;
307
- }
308
- }
309
-
310
- if (accountId === me && !deleteHistory && chatList?.data) {
311
- const listItem = chatList.data.find((x) => x.id === chatId)!;
312
- listItem.active = false;
313
- }
314
-
315
- if ((accountId !== me || !deleteHistory) && state.query.messages[chatId].data) {
316
- state.query.messages[chatId].data!.unshift({ ...message, type: 'message' });
317
- }
318
-
319
- if ((accountId !== me || !deleteHistory) && state.query.chatList.data) {
320
- const listItem = state.query.chatList.data.find((x) => x.id === chatId)!;
321
- listItem.message = message;
322
- listItem.totalUnreadCount++;
323
- }
324
-
325
- if (accountId === me && deleteHistory && state.query.messages[chatId].data) {
326
- delete state.query.messages[chatId];
327
- }
328
- },
329
-
330
- chat_fetch: (state: State, { chatId }: { chatId: string }) => {
331
- state.query.chats[chatId] = { isFetching: true, uninitialized: false, data: undefined, error: undefined };
332
- },
333
-
334
- chat_fulfilled: (state: State, { chat }: { chat: Chat }) => {
335
- const chatState = state.query.chats[chat.id];
336
- chatState.isFetching = false;
337
- chatState.error = undefined;
338
- chatState.data = chat;
339
- },
340
-
341
- chat_rejected: (state: State, { chatId, error }: { chatId: string; error: any }) => {
342
- const chatState = state.query.chats[chatId];
343
- chatState.isFetching = false;
344
- chatState.error = error;
345
- },
346
-
347
- send_fetch: (
348
- state: State,
349
- {
350
- chatId,
351
- text,
352
- files,
353
- requestId,
354
- }: {
355
- chatId: string;
356
- text: string;
357
- files: File[];
358
- requestId: string;
359
- },
360
- ) => {
361
- state.mutation.send = { isFetching: true, error: undefined };
362
- state.query.messages[chatId].data?.push({ type: 'sending', text, files, requestId });
363
- },
364
-
365
- send_fulfilled: (state: State, { chatId, requestId }: { chatId: string; requestId: string }) => {
366
- state.mutation.send = { isFetching: false, error: undefined };
367
- },
368
-
369
- send_rejected: (
370
- state: State,
371
- { chatId, requestId, error }: { chatId: string; requestId: string; error: any },
372
- ) => {
373
- state.mutation.send = { isFetching: false, error };
374
- state.query.messages[chatId].data = state.query.messages[chatId].data?.filter(
375
- (x) => x.type !== 'sending' || x.requestId !== requestId,
376
- );
377
- },
378
-
379
- chatNameChanged_received: (
380
- state: State,
381
- { chatId, newName, message }: { chatId: string; newName: string; message: Message },
382
- ) => {
383
- if (state.query.chatList.data) {
384
- const chatListItem = state.query.chatList.data.find((x) => x.id === chatId);
385
- chatListItem!.name = newName;
386
- chatListItem!.message = message;
387
- chatListItem!.totalUnreadCount++;
388
- }
389
-
390
- if (state.query.chats[chatId].data) {
391
- state.query.chats[chatId].data!.name = newName;
392
- }
393
-
394
- if (state.query.messages[chatId].data) {
395
- state.query.messages[chatId].data!.unshift({ type: 'message', ...message });
396
- }
397
- },
398
- };
399
-
400
- export type Action = {
401
- [K in keyof typeof ACTIONS]: {
402
- type: K;
403
- data: Parameters<(typeof ACTIONS)[K]>[1];
404
- };
405
- }[keyof typeof ACTIONS];
1
+ import type { State } from './state';
2
+ import { Account, Chat, ChatListItem, Message, ReadEvent, File } from './models';
3
+
4
+ export const ACTIONS = {
5
+ update: (state: State, { mutation }: { mutation: (state: State) => State }) => {
6
+ mutation(state);
7
+ },
8
+
9
+ messages_fetch: (state: State, { chatId, requestId }: { chatId: string; requestId: string }) => {
10
+ state.query.messages[chatId] = {
11
+ ...state.query.messages[chatId],
12
+ uninitialized: false,
13
+ isFetching: true,
14
+ requestId,
15
+ };
16
+ },
17
+
18
+ messages_fulfilled: (
19
+ state: State,
20
+ { chatId, messages, hasMore }: { chatId: string; messages: Message[]; hasMore: boolean },
21
+ ) => {
22
+ const qState = state.query.messages[chatId];
23
+
24
+ qState.error = undefined;
25
+ qState.isFetching = false;
26
+ qState.data = messages.map((x) => ({ type: 'message', ...x }));
27
+ qState.requestId = undefined;
28
+
29
+ if (hasMore) {
30
+ qState.data!.push({ type: 'next' });
31
+ }
32
+ },
33
+
34
+ messages_rejected: (state: State, { chatId, error }: { chatId: string; error: any }) => {
35
+ const qState = state.query.messages[chatId];
36
+ qState.error = error;
37
+ qState.isFetching = false;
38
+ qState.requestId = undefined;
39
+ },
40
+
41
+ fetchNext_fetch: (state: State, { chatId }: { chatId: string }) => {
42
+ state.mutation.fetchNext = { isFetching: true };
43
+ },
44
+
45
+ fetchNext_fulfilled: (
46
+ state: State,
47
+ { chatId, messages, hasMore }: { chatId: string; messages: Message[]; hasMore: boolean },
48
+ ) => {
49
+ state.mutation.fetchNext = { isFetching: false, error: undefined };
50
+ state.query.messages[chatId].data = state.query.messages[chatId].data!.filter((x) => x.type !== 'next');
51
+ state.query.messages[chatId].data!.push(...messages.map((x) => ({ type: 'message' as const, ...x })));
52
+
53
+ if (hasMore) state.query.messages[chatId].data!.push({ type: 'next' });
54
+ },
55
+
56
+ fetchNext_rejected: (state: State, { chatId, error }: { chatId: string; error: any }) => {
57
+ state.mutation.fetchNext = { isFetching: false, error };
58
+ },
59
+
60
+ chatList_fetch: (state: State, { requestId }: { requestId: string }) => {
61
+ state.query.chatList.isFetching = true;
62
+ state.query.chatList.uninitialized = false;
63
+ state.query.chatList.requestId = requestId;
64
+ },
65
+
66
+ chatList_fulfilled: (state: State, { chats }: { chats: ChatListItem[] }) => {
67
+ chats = chats.sort((a, b) => -a.message.id.substring(47).localeCompare(b.message.id.substring(47)));
68
+
69
+ state.query.chatList.isFetching = false;
70
+ state.query.chatList.error = undefined;
71
+ state.query.chatList.data = chats;
72
+ state.query.chatList.requestId = undefined;
73
+
74
+ if (state.ui.chatId === undefined && chats.length > 0) {
75
+ state.ui.view = 'chat';
76
+ state.ui.chatId = chats[0].id;
77
+ }
78
+ },
79
+
80
+ chatList_rejected: (state: State, { error }: { error: any }) => {
81
+ state.query.chatList.isFetching = false;
82
+ state.query.chatList.error = error;
83
+ state.query.chatList.requestId = undefined;
84
+ },
85
+
86
+ removeMember_fetch: (state: State) => {
87
+ state.mutation.removeMember = { isFetching: true };
88
+ },
89
+
90
+ removeMember_fulfilled: (state: State) => {
91
+ state.mutation.removeMember = { isFetching: false, error: undefined };
92
+ },
93
+
94
+ removeMember_rejected: (state: State, { error }: { error: any }) => {
95
+ state.mutation.removeMember = { isFetching: false, error };
96
+ },
97
+
98
+ addMember_fetch: (state: State) => {
99
+ state.mutation.addMember = { isFetching: true };
100
+ },
101
+
102
+ addMember_fulfilled: (state: State) => {
103
+ state.mutation.addMember = { isFetching: false, error: undefined };
104
+ },
105
+
106
+ addMember_rejected: (state: State, { error }: { error: any }) => {
107
+ state.mutation.addMember = { isFetching: false, error };
108
+ },
109
+
110
+ updateChatName_fetch: (state: State) => {
111
+ state.mutation.updateChatName = { isFetching: true };
112
+ },
113
+
114
+ updateChatName_fulfilled: (state: State) => {
115
+ state.mutation.updateChatName = { isFetching: false, error: undefined };
116
+ },
117
+
118
+ updateChatName_rejected: (state: State, { error }: { error: any }) => {
119
+ state.mutation.updateChatName = { isFetching: false, error };
120
+ },
121
+
122
+ addChat_fetch: (state: State) => {
123
+ state.mutation.addChat = { isFetching: true };
124
+ },
125
+
126
+ addChat_fulfilled: (state: State) => {
127
+ state.mutation.addChat = { isFetching: false, error: undefined };
128
+ },
129
+
130
+ addChat_rejected: (state: State, { error }: { error: any }) => {
131
+ state.mutation.addChat = { isFetching: false, error };
132
+ },
133
+
134
+ accounts_fetch: (state: State, { requestId }: { requestId: string }) => {
135
+ state.query.accounts = { isFetching: true, uninitialized: false, requestId };
136
+ },
137
+
138
+ accounts_fulfilled: (state: State, { accounts }: { accounts: Account[] }) => {
139
+ state.query.accounts.data = accounts;
140
+ state.query.accounts.isFetching = false;
141
+ state.query.accounts.error = undefined;
142
+ state.query.accounts.requestId = undefined;
143
+ },
144
+
145
+ accounts_rejected: (state: State, { error }: { error: any }) => {
146
+ state.query.accounts.isFetching = false;
147
+ state.query.accounts.error = error;
148
+ state.query.accounts.requestId = undefined;
149
+ },
150
+
151
+ chat_open: (state: State, { chatId }: { chatId: string }) => {
152
+ state.ui.chatId = chatId;
153
+ state.ui.view = 'chat';
154
+ },
155
+
156
+ new_chat_open: (state: State) => {
157
+ state.ui.chatId = undefined;
158
+ state.ui.view = 'new-chat';
159
+ },
160
+
161
+ toggle_members_view: (state: State) => {
162
+ state.ui.showMembers = !state.ui.showMembers;
163
+ },
164
+
165
+ message_received: (
166
+ state: State,
167
+ { message, requestId, me }: { message: Message; requestId: string; me: string },
168
+ ) => {
169
+ const messagesState = state.query.messages[message.chatId];
170
+
171
+ if (messagesState?.data) {
172
+ messagesState.data.unshift({ type: 'message', ...message });
173
+ messagesState.data = messagesState.data.filter(
174
+ (x) => x.type !== 'sending' || x.requestId !== requestId,
175
+ );
176
+ }
177
+
178
+ const chatListItemState = state.query.chatList?.data?.find((x) => x.id === message.chatId);
179
+
180
+ if (chatListItemState) {
181
+ chatListItemState.message = message;
182
+ }
183
+
184
+ if (chatListItemState && message.sentBy.id !== me) {
185
+ chatListItemState.totalUnreadCount++;
186
+ }
187
+
188
+ if (chatListItemState && message.sentBy.id === me) {
189
+ chatListItemState.lastReadMessageId = message.id;
190
+ chatListItemState.totalUnreadCount = 0;
191
+ }
192
+ },
193
+
194
+ chat_created: (state: State, { chat }: { chat: ChatListItem; requestId?: string }) => {
195
+ state.query.chatList?.data?.unshift(chat);
196
+ },
197
+
198
+ read: (state: State, { id, timestamp }: { id: string; timestamp: number }) => {
199
+ const queuedSameChat = state.queue.read.queued.filter((x) => x.substring(0, 36) === id.substring(0, 36));
200
+
201
+ if (queuedSameChat.some((x) => x.localeCompare(id) >= 0)) {
202
+ return;
203
+ }
204
+
205
+ state.queue.read.queued.filter((x) => queuedSameChat.includes(x));
206
+ state.queue.read.queued.push(id);
207
+ state.queue.read.timestamp = timestamp;
208
+ },
209
+
210
+ read_send: (state: State, { id }: { id: string }) => {
211
+ state.queue.read.queued = state.queue.read.queued.filter((x) => x !== id);
212
+ state.queue.read.processing.push(id);
213
+ },
214
+
215
+ read_reject: (state: State, { id, timestamp }: { id: string; timestamp: number }) => {
216
+ state.queue.read.queued.push(id);
217
+ state.queue.read.processing = state.queue.read.processing.filter((x) => x !== id);
218
+ state.queue.read.timestamp = timestamp;
219
+ },
220
+
221
+ read_received: (state: State, { events }: { events: ReadEvent[] }) => {
222
+ state.queue.read.processing = state.queue.read.processing.filter((item) => {
223
+ const event = events.find((x) => x.chatId === item.substring(0, 36));
224
+ return !event || event.newLastReadMessageId.localeCompare(item) >= 0;
225
+ });
226
+
227
+ for (const event of events) {
228
+ state.queue.read.processing = state.queue.read.processing.filter(
229
+ (x) => x.substring(0, 36) !== event.chatId || x.localeCompare(event.newLastReadMessageId) > 0,
230
+ );
231
+ const chatListItem = state.query.chatList.data?.find((x) => x.id === event.chatId);
232
+
233
+ if (chatListItem) {
234
+ chatListItem.lastReadMessageId = event.newLastReadMessageId;
235
+ chatListItem.totalUnreadCount = chatListItem.totalUnreadCount - event.readCount;
236
+ }
237
+ }
238
+ },
239
+
240
+ member_added: (
241
+ state: State,
242
+ {
243
+ chatId,
244
+ chatName,
245
+ account,
246
+ me,
247
+ message,
248
+ withHistory,
249
+ }: {
250
+ chatId: string;
251
+ chatName: string;
252
+ account: Account;
253
+ me: string;
254
+ message: Message;
255
+ withHistory: boolean;
256
+ },
257
+ ) => {
258
+ const { chats, messages, chatList } = state.query;
259
+ chats[chatId]?.data?.members.push(account);
260
+ const chatListItem = chatList?.data?.find((x) => x.id === chatId);
261
+
262
+ if (account.id !== me && chatListItem != null) {
263
+ chatListItem.message = message;
264
+ chatListItem.totalUnreadCount++;
265
+ }
266
+
267
+ messages[chatId]?.data?.unshift({ type: 'message', ...message });
268
+
269
+ if (account.id === me && chatList.data !== undefined && !chatListItem) {
270
+ chatList.data.unshift({
271
+ id: chatId,
272
+ name: chatName,
273
+ message,
274
+ totalUnreadCount: 1,
275
+ active: true,
276
+ lastReadMessageId: null,
277
+ });
278
+ }
279
+
280
+ if (account.id === me && chatListItem) {
281
+ chatListItem.active = true;
282
+ chatListItem.message = message;
283
+ chatListItem.totalUnreadCount++;
284
+ }
285
+
286
+ return state;
287
+ },
288
+
289
+ member_removed: (
290
+ state: State,
291
+ {
292
+ chatId,
293
+ accountId,
294
+ deleteHistory,
295
+ me,
296
+ message,
297
+ }: { chatId: string; accountId: string; deleteHistory: boolean; me: string; message: Message },
298
+ ) => {
299
+ const { chats, chatList } = state.query;
300
+ const chat = chats[chatId];
301
+
302
+ if (chat?.data) {
303
+ chat.data.members = chat.data.members.filter((x) => x.id !== accountId);
304
+ }
305
+
306
+ if (accountId === me && state.query.chats[chatId].data) {
307
+ delete state.query.chats[chatId];
308
+ }
309
+
310
+ if (accountId === me && deleteHistory && chatList?.data) {
311
+ chatList.data = chatList.data.filter((x) => x.id !== chatId);
312
+
313
+ if (state.ui.chatId === chatId) {
314
+ state.ui.chatId = chatList.data.at(0)?.id;
315
+ }
316
+ }
317
+
318
+ if (accountId === me && !deleteHistory && chatList?.data) {
319
+ const listItem = chatList.data.find((x) => x.id === chatId)!;
320
+ listItem.active = false;
321
+ }
322
+
323
+ if ((accountId !== me || !deleteHistory) && state.query.messages[chatId].data) {
324
+ state.query.messages[chatId].data!.unshift({ ...message, type: 'message' });
325
+ }
326
+
327
+ if ((accountId !== me || !deleteHistory) && state.query.chatList.data) {
328
+ const listItem = state.query.chatList.data.find((x) => x.id === chatId)!;
329
+ listItem.message = message;
330
+ listItem.totalUnreadCount++;
331
+ }
332
+
333
+ if (accountId === me && deleteHistory && state.query.messages[chatId].data) {
334
+ delete state.query.messages[chatId];
335
+ }
336
+ },
337
+
338
+ chat_fetch: (state: State, { chatId, requestId }: { chatId: string; requestId: string }) => {
339
+ state.query.chats[chatId] = {
340
+ isFetching: true,
341
+ uninitialized: false,
342
+ data: undefined,
343
+ error: undefined,
344
+ requestId,
345
+ };
346
+ },
347
+
348
+ chat_fulfilled: (state: State, { chat }: { chat: Chat }) => {
349
+ const chatState = state.query.chats[chat.id];
350
+ chatState.isFetching = false;
351
+ chatState.error = undefined;
352
+ chatState.data = chat;
353
+ chatState.requestId = undefined;
354
+ },
355
+
356
+ chat_rejected: (state: State, { chatId, error }: { chatId: string; error: any }) => {
357
+ const chatState = state.query.chats[chatId];
358
+ chatState.isFetching = false;
359
+ chatState.error = error;
360
+ chatState.requestId = undefined;
361
+ },
362
+
363
+ send_fetch: (
364
+ state: State,
365
+ {
366
+ chatId,
367
+ text,
368
+ files,
369
+ requestId,
370
+ }: {
371
+ chatId: string;
372
+ text: string;
373
+ files: File[];
374
+ requestId: string;
375
+ },
376
+ ) => {
377
+ state.mutation.send = { isFetching: true, error: undefined };
378
+ state.query.messages[chatId].data?.push({ type: 'sending', text, files, requestId });
379
+ },
380
+
381
+ send_fulfilled: (state: State, { chatId, requestId }: { chatId: string; requestId: string }) => {
382
+ state.mutation.send = { isFetching: false, error: undefined };
383
+ },
384
+
385
+ send_rejected: (
386
+ state: State,
387
+ { chatId, requestId, error }: { chatId: string; requestId: string; error: any },
388
+ ) => {
389
+ state.mutation.send = { isFetching: false, error };
390
+ state.query.messages[chatId].data = state.query.messages[chatId].data?.filter(
391
+ (x) => x.type !== 'sending' || x.requestId !== requestId,
392
+ );
393
+ },
394
+
395
+ chatNameChanged_received: (
396
+ state: State,
397
+ { chatId, newName, message }: { chatId: string; newName: string; message: Message },
398
+ ) => {
399
+ if (state.query.chatList.data) {
400
+ const chatListItem = state.query.chatList.data.find((x) => x.id === chatId);
401
+ chatListItem!.name = newName;
402
+ chatListItem!.message = message;
403
+ chatListItem!.totalUnreadCount++;
404
+ }
405
+
406
+ if (state.query.chats[chatId].data) {
407
+ state.query.chats[chatId].data!.name = newName;
408
+ }
409
+
410
+ if (state.query.messages[chatId].data) {
411
+ state.query.messages[chatId].data!.unshift({ type: 'message', ...message });
412
+ }
413
+ },
414
+ };
415
+
416
+ export type Action = {
417
+ [K in keyof typeof ACTIONS]: {
418
+ type: K;
419
+ data: Parameters<(typeof ACTIONS)[K]>[1];
420
+ };
421
+ }[keyof typeof ACTIONS];