stream-chat 9.0.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.browser.cjs +104 -72
- package/dist/cjs/index.browser.cjs.map +3 -3
- package/dist/cjs/index.node.cjs +104 -72
- package/dist/cjs/index.node.cjs.map +3 -3
- package/dist/esm/index.js +104 -72
- package/dist/esm/index.js.map +3 -3
- package/dist/types/client.d.ts +3 -3
- package/dist/types/constants.d.ts +21 -3
- package/dist/types/messageComposer/middleware/messageComposer/pollOnly.d.ts +3 -0
- package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +1 -0
- package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts +1 -1
- package/dist/types/messageComposer/pollComposer.d.ts +7 -2
- package/dist/types/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/client.ts +21 -16
- package/src/constants.ts +19 -20
- package/src/messageComposer/messageComposer.ts +5 -6
- package/src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts +2 -0
- package/src/messageComposer/middleware/messageComposer/pollOnly.ts +49 -0
- package/src/messageComposer/middleware/pollComposer/state.ts +11 -3
- package/src/messageComposer/middleware/pollComposer/types.ts +1 -0
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -24
- package/src/messageComposer/pollComposer.ts +16 -2
- package/src/types.ts +2 -17
- package/src/utils.ts +6 -7
package/dist/types/client.d.ts
CHANGED
|
@@ -1064,12 +1064,12 @@ export declare class StreamChat {
|
|
|
1064
1064
|
* updateMessage - Update the given message
|
|
1065
1065
|
*
|
|
1066
1066
|
* @param {Omit<MessageResponse, 'mentioned_users'> & { mentioned_users?: string[] }} message object, id needs to be specified
|
|
1067
|
-
* @param {string | { id: string }} [
|
|
1067
|
+
* @param {string | { id: string }} [partialUserOrUserId]
|
|
1068
1068
|
* @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message
|
|
1069
1069
|
*
|
|
1070
1070
|
* @return {{ message: LocalMessage | MessageResponse }} Response that includes the message
|
|
1071
1071
|
*/
|
|
1072
|
-
updateMessage(message: LocalMessage | Partial<MessageResponse>,
|
|
1072
|
+
updateMessage(message: LocalMessage | Partial<MessageResponse>, partialUserOrUserId?: string | {
|
|
1073
1073
|
id: string;
|
|
1074
1074
|
}, options?: UpdateMessageOptions): Promise<UpdateMessageAPIResponse>;
|
|
1075
1075
|
/**
|
|
@@ -1085,7 +1085,7 @@ export declare class StreamChat {
|
|
|
1085
1085
|
*
|
|
1086
1086
|
* @return {{ message: MessageResponse }} Response that includes the updated message
|
|
1087
1087
|
*/
|
|
1088
|
-
partialUpdateMessage(id: string, partialMessageObject: PartialMessageUpdate,
|
|
1088
|
+
partialUpdateMessage(id: string, partialMessageObject: PartialMessageUpdate, partialUserOrUserId?: string | {
|
|
1089
1089
|
id: string;
|
|
1090
1090
|
}, options?: UpdateMessageOptions): Promise<UpdateMessageAPIResponse>;
|
|
1091
1091
|
deleteMessage(messageID: string, hardDelete?: boolean): Promise<APIResponse & {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ReservedUpdatedMessageFields } from './types';
|
|
2
1
|
export declare const DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE = 25;
|
|
3
2
|
export declare const DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE = 100;
|
|
4
3
|
export declare const DEFAULT_MESSAGE_SET_PAGINATION: {
|
|
@@ -8,5 +7,24 @@ export declare const DEFAULT_MESSAGE_SET_PAGINATION: {
|
|
|
8
7
|
export declare const DEFAULT_UPLOAD_SIZE_LIMIT_BYTES: number;
|
|
9
8
|
export declare const API_MAX_FILES_ALLOWED_PER_MESSAGE = 10;
|
|
10
9
|
export declare const MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY = 100;
|
|
11
|
-
export declare const RESERVED_UPDATED_MESSAGE_FIELDS:
|
|
12
|
-
|
|
10
|
+
export declare const RESERVED_UPDATED_MESSAGE_FIELDS: {
|
|
11
|
+
readonly created_at: true;
|
|
12
|
+
readonly deleted_at: true;
|
|
13
|
+
readonly pinned_at: true;
|
|
14
|
+
readonly updated_at: true;
|
|
15
|
+
readonly command: true;
|
|
16
|
+
readonly mentioned_users: true;
|
|
17
|
+
readonly quoted_message: true;
|
|
18
|
+
readonly latest_reactions: true;
|
|
19
|
+
readonly own_reactions: true;
|
|
20
|
+
readonly reaction_counts: true;
|
|
21
|
+
readonly reply_count: true;
|
|
22
|
+
readonly i18n: true;
|
|
23
|
+
readonly type: true;
|
|
24
|
+
readonly html: true;
|
|
25
|
+
readonly __html: true;
|
|
26
|
+
readonly user: true;
|
|
27
|
+
};
|
|
28
|
+
export declare const LOCAL_MESSAGE_FIELDS: {
|
|
29
|
+
readonly error: true;
|
|
30
|
+
};
|
|
@@ -43,6 +43,7 @@ export type PollComposerStateChangeMiddlewareValue = {
|
|
|
43
43
|
targetFields: Partial<{
|
|
44
44
|
[K in keyof PollComposerState['data']]: K extends 'options' ? PollComposerOptionUpdate : PollComposerState['data'][K];
|
|
45
45
|
}>;
|
|
46
|
+
injectedFieldErrors?: PollComposerFieldErrors;
|
|
46
47
|
};
|
|
47
48
|
export type PollComposerStateMiddlewareValue = MiddlewareExecutionResult<PollComposerStateChangeMiddlewareValue>;
|
|
48
49
|
export {};
|
package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
|
|
2
1
|
import { MiddlewareExecutor } from '../../../middleware';
|
|
2
|
+
import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
|
|
3
3
|
import type { Suggestion, TextComposerMiddlewareExecutorOptions, TextComposerState } from './types';
|
|
4
4
|
export type TextComposerMiddlewareExecutorState<T extends Suggestion = Suggestion> = TextComposerState<T> & {
|
|
5
5
|
change?: {
|
|
@@ -2,7 +2,7 @@ import { PollComposerCompositionMiddlewareExecutor, PollComposerStateMiddlewareE
|
|
|
2
2
|
import { StateStore } from '../store';
|
|
3
3
|
import { VotingVisibility } from '../types';
|
|
4
4
|
import type { MessageComposer } from './messageComposer';
|
|
5
|
-
import type { PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
|
|
5
|
+
import type { PollComposerFieldErrors, PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
|
|
6
6
|
export type PollComposerOptions = {
|
|
7
7
|
composer: MessageComposer;
|
|
8
8
|
};
|
|
@@ -25,7 +25,12 @@ export declare class PollComposer {
|
|
|
25
25
|
get voting_visibility(): VotingVisibility | undefined;
|
|
26
26
|
get canCreatePoll(): boolean;
|
|
27
27
|
initState: () => void;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Updates specified fields and generates relevant errors
|
|
30
|
+
* @param data
|
|
31
|
+
* @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing
|
|
32
|
+
*/
|
|
33
|
+
updateFields: (data: UpdateFieldsData, injectedFieldErrors?: PollComposerFieldErrors) => Promise<void>;
|
|
29
34
|
handleFieldBlur: (field: keyof PollComposerState["data"]) => Promise<void>;
|
|
30
35
|
compose: () => Promise<import("..").PollComposerCompositionMiddlewareValueState | undefined>;
|
|
31
36
|
}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { StableWSConnection } from './connection';
|
|
|
5
5
|
import type { Role } from './permissions';
|
|
6
6
|
import type { CustomAttachmentData, CustomChannelData, CustomCommandData, CustomEventData, CustomMemberData, CustomMessageData, CustomPollData, CustomPollOptionData, CustomReactionData, CustomThreadData, CustomUserData } from './custom_types';
|
|
7
7
|
import type { NotificationManager } from './notifications';
|
|
8
|
+
import type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';
|
|
8
9
|
/**
|
|
9
10
|
* Utility Types
|
|
10
11
|
*/
|
|
@@ -2122,7 +2123,7 @@ export type TokenOrProvider = null | string | TokenProvider | undefined;
|
|
|
2122
2123
|
export type TokenProvider = () => Promise<string>;
|
|
2123
2124
|
export type TranslationLanguages = 'af' | 'am' | 'ar' | 'az' | 'bg' | 'bn' | 'bs' | 'cs' | 'da' | 'de' | 'el' | 'en' | 'es' | 'es-MX' | 'et' | 'fa' | 'fa-AF' | 'fi' | 'fr' | 'fr-CA' | 'ha' | 'he' | 'hi' | 'hr' | 'hu' | 'id' | 'it' | 'ja' | 'ka' | 'ko' | 'lt' | 'lv' | 'ms' | 'nl' | 'no' | 'pl' | 'ps' | 'pt' | 'ro' | 'ru' | 'sk' | 'sl' | 'so' | 'sq' | 'sr' | 'sv' | 'sw' | 'ta' | 'th' | 'tl' | 'tr' | 'uk' | 'ur' | 'vi' | 'zh' | 'zh-TW' | (string & {});
|
|
2124
2125
|
export type TypingStartEvent = Event;
|
|
2125
|
-
export type ReservedUpdatedMessageFields =
|
|
2126
|
+
export type ReservedUpdatedMessageFields = keyof typeof RESERVED_UPDATED_MESSAGE_FIELDS;
|
|
2126
2127
|
export type UpdatedMessage = Omit<MessageResponse, ReservedUpdatedMessageFields> & {
|
|
2127
2128
|
mentioned_users?: string[];
|
|
2128
2129
|
type?: MessageLabel;
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -2860,28 +2860,28 @@ export class StreamChat {
|
|
|
2860
2860
|
* updateMessage - Update the given message
|
|
2861
2861
|
*
|
|
2862
2862
|
* @param {Omit<MessageResponse, 'mentioned_users'> & { mentioned_users?: string[] }} message object, id needs to be specified
|
|
2863
|
-
* @param {string | { id: string }} [
|
|
2863
|
+
* @param {string | { id: string }} [partialUserOrUserId]
|
|
2864
2864
|
* @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message
|
|
2865
2865
|
*
|
|
2866
2866
|
* @return {{ message: LocalMessage | MessageResponse }} Response that includes the message
|
|
2867
2867
|
*/
|
|
2868
2868
|
async updateMessage(
|
|
2869
2869
|
message: LocalMessage | Partial<MessageResponse>,
|
|
2870
|
-
|
|
2870
|
+
partialUserOrUserId?: string | { id: string },
|
|
2871
2871
|
options?: UpdateMessageOptions,
|
|
2872
2872
|
) {
|
|
2873
2873
|
if (!message.id) {
|
|
2874
|
-
throw Error('Please specify the message
|
|
2874
|
+
throw Error('Please specify the message.id when calling updateMessage');
|
|
2875
2875
|
}
|
|
2876
|
+
|
|
2877
|
+
// should not include user object
|
|
2876
2878
|
const payload = toUpdatedMessagePayload(message);
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
};
|
|
2884
|
-
}
|
|
2879
|
+
|
|
2880
|
+
// add user_id (if exists)
|
|
2881
|
+
if (typeof partialUserOrUserId === 'string') {
|
|
2882
|
+
payload.user_id = partialUserOrUserId;
|
|
2883
|
+
} else if (typeof partialUserOrUserId?.id === 'string') {
|
|
2884
|
+
payload.user_id = partialUserOrUserId.id;
|
|
2885
2885
|
}
|
|
2886
2886
|
|
|
2887
2887
|
return await this.post<UpdateMessageAPIResponse>(
|
|
@@ -2909,16 +2909,21 @@ export class StreamChat {
|
|
|
2909
2909
|
async partialUpdateMessage(
|
|
2910
2910
|
id: string,
|
|
2911
2911
|
partialMessageObject: PartialMessageUpdate,
|
|
2912
|
-
|
|
2912
|
+
partialUserOrUserId?: string | { id: string },
|
|
2913
2913
|
options?: UpdateMessageOptions,
|
|
2914
2914
|
) {
|
|
2915
2915
|
if (!id) {
|
|
2916
|
-
throw Error('Please specify the message
|
|
2916
|
+
throw Error('Please specify the message.id when calling partialUpdateMessage');
|
|
2917
2917
|
}
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2918
|
+
|
|
2919
|
+
let user: { id: string } | undefined = undefined;
|
|
2920
|
+
|
|
2921
|
+
if (typeof partialUserOrUserId === 'string') {
|
|
2922
|
+
user = { id: partialUserOrUserId };
|
|
2923
|
+
} else if (typeof partialUserOrUserId?.id === 'string') {
|
|
2924
|
+
user = { id: partialUserOrUserId.id };
|
|
2921
2925
|
}
|
|
2926
|
+
|
|
2922
2927
|
return await this.put<UpdateMessageAPIResponse>(
|
|
2923
2928
|
this.baseURL + `/messages/${encodeURIComponent(id)}`,
|
|
2924
2929
|
{
|
package/src/constants.ts
CHANGED
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
import type { ReservedUpdatedMessageFields } from './types';
|
|
2
|
-
|
|
3
1
|
export const DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE = 25;
|
|
4
2
|
export const DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE = 100;
|
|
5
3
|
export const DEFAULT_MESSAGE_SET_PAGINATION = { hasNext: false, hasPrev: false };
|
|
6
4
|
export const DEFAULT_UPLOAD_SIZE_LIMIT_BYTES = 100 * 1024 * 1024; // 100 MB
|
|
7
5
|
export const API_MAX_FILES_ALLOWED_PER_MESSAGE = 10;
|
|
8
6
|
export const MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY = 100;
|
|
9
|
-
export const RESERVED_UPDATED_MESSAGE_FIELDS
|
|
7
|
+
export const RESERVED_UPDATED_MESSAGE_FIELDS = {
|
|
10
8
|
// Dates should not be converted back to ISO strings as JS looses precision on them (milliseconds)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
created_at: true,
|
|
10
|
+
deleted_at: true,
|
|
11
|
+
pinned_at: true,
|
|
12
|
+
updated_at: true,
|
|
13
|
+
command: true,
|
|
16
14
|
// Back-end enriches these fields
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
mentioned_users: true,
|
|
16
|
+
quoted_message: true,
|
|
19
17
|
// Client-specific fields
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
latest_reactions: true,
|
|
19
|
+
own_reactions: true,
|
|
20
|
+
reaction_counts: true,
|
|
21
|
+
reply_count: true,
|
|
24
22
|
// Message text related fields that shouldn't be in update
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
i18n: true,
|
|
24
|
+
type: true,
|
|
25
|
+
html: true,
|
|
26
|
+
__html: true,
|
|
27
|
+
user: true,
|
|
28
|
+
} as const;
|
|
30
29
|
|
|
31
|
-
export const LOCAL_MESSAGE_FIELDS =
|
|
30
|
+
export const LOCAL_MESSAGE_FIELDS = { error: true } as const;
|
|
@@ -88,16 +88,18 @@ const initState = (
|
|
|
88
88
|
const quotedMessage = composition.quoted_message;
|
|
89
89
|
let message;
|
|
90
90
|
let draftId = null;
|
|
91
|
+
let id = MessageComposer.generateId(); // do not use draft id for messsage id
|
|
91
92
|
if (compositionIsDraftResponse(composition)) {
|
|
92
93
|
message = composition.message;
|
|
93
94
|
draftId = composition.message.id;
|
|
94
95
|
} else {
|
|
95
96
|
message = composition;
|
|
97
|
+
id = composition.id;
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
return {
|
|
99
101
|
draftId,
|
|
100
|
-
id
|
|
102
|
+
id,
|
|
101
103
|
quotedMessage: quotedMessage
|
|
102
104
|
? formatMessage(quotedMessage as MessageResponseBase)
|
|
103
105
|
: null,
|
|
@@ -318,6 +320,7 @@ export class MessageComposer {
|
|
|
318
320
|
this.attachmentManager.initState({ message });
|
|
319
321
|
this.linkPreviewsManager.initState({ message });
|
|
320
322
|
this.textComposer.initState({ message });
|
|
323
|
+
this.pollComposer.initState();
|
|
321
324
|
this.customDataManager.initState({ message });
|
|
322
325
|
this.state.next(initState(composition));
|
|
323
326
|
if (
|
|
@@ -543,11 +546,6 @@ export class MessageComposer {
|
|
|
543
546
|
};
|
|
544
547
|
|
|
545
548
|
clear = () => {
|
|
546
|
-
this.attachmentManager.initState();
|
|
547
|
-
this.linkPreviewsManager.initState();
|
|
548
|
-
this.textComposer.initState();
|
|
549
|
-
this.pollComposer.initState();
|
|
550
|
-
this.customDataManager.initState();
|
|
551
549
|
this.initState();
|
|
552
550
|
};
|
|
553
551
|
|
|
@@ -630,6 +628,7 @@ export class MessageComposer {
|
|
|
630
628
|
try {
|
|
631
629
|
const { poll } = await this.client.createPoll(composition.data);
|
|
632
630
|
this.state.partialNext({ pollId: poll.id });
|
|
631
|
+
this.pollComposer.initState();
|
|
633
632
|
} catch (error) {
|
|
634
633
|
this.client.notifications.add({
|
|
635
634
|
message: 'Failed to create the poll',
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
createCustomDataCompositionMiddleware,
|
|
31
31
|
createDraftCustomDataCompositionMiddleware,
|
|
32
32
|
} from './customData';
|
|
33
|
+
import { createPollOnlyCompositionMiddleware } from './pollOnly';
|
|
33
34
|
|
|
34
35
|
export class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<
|
|
35
36
|
MessageComposerMiddlewareState,
|
|
@@ -40,6 +41,7 @@ export class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<
|
|
|
40
41
|
// todo: document how to add custom data to a composed message using middleware
|
|
41
42
|
// or adding custom composer components (apart from AttachmentsManager, TextComposer etc.)
|
|
42
43
|
this.use([
|
|
44
|
+
createPollOnlyCompositionMiddleware(composer),
|
|
43
45
|
createTextComposerCompositionMiddleware(composer),
|
|
44
46
|
createAttachmentsCompositionMiddleware(composer),
|
|
45
47
|
createLinkPreviewsCompositionMiddleware(composer),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MessageComposerMiddlewareState,
|
|
3
|
+
MessageCompositionMiddleware,
|
|
4
|
+
} from './types';
|
|
5
|
+
import type { MessageComposer } from '../../messageComposer';
|
|
6
|
+
import type { MiddlewareHandlerParams } from '../../../middleware';
|
|
7
|
+
import type { LocalMessage } from '../../../types';
|
|
8
|
+
|
|
9
|
+
const pollLocalMessageNullifiedFields: Pick<
|
|
10
|
+
LocalMessage,
|
|
11
|
+
'attachments' | 'mentioned_users' | 'parent_id' | 'quoted_message' | 'text'
|
|
12
|
+
> = {
|
|
13
|
+
attachments: [],
|
|
14
|
+
mentioned_users: [],
|
|
15
|
+
parent_id: undefined,
|
|
16
|
+
quoted_message: undefined,
|
|
17
|
+
text: '',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const createPollOnlyCompositionMiddleware = (
|
|
21
|
+
composer: MessageComposer,
|
|
22
|
+
): MessageCompositionMiddleware => ({
|
|
23
|
+
id: 'stream-io/message-composer-middleware/poll-only',
|
|
24
|
+
handlers: {
|
|
25
|
+
compose: ({
|
|
26
|
+
state,
|
|
27
|
+
complete,
|
|
28
|
+
forward,
|
|
29
|
+
}: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {
|
|
30
|
+
const pollId = composer.pollId;
|
|
31
|
+
const isEditingMessage = !!composer.editedMessage;
|
|
32
|
+
const isComposingThreadReply = !!composer.threadId;
|
|
33
|
+
if (!pollId || isComposingThreadReply || isEditingMessage) return forward();
|
|
34
|
+
|
|
35
|
+
return complete({
|
|
36
|
+
...state,
|
|
37
|
+
localMessage: {
|
|
38
|
+
...state.localMessage,
|
|
39
|
+
...pollLocalMessageNullifiedFields,
|
|
40
|
+
poll_id: pollId,
|
|
41
|
+
},
|
|
42
|
+
message: {
|
|
43
|
+
id: state.localMessage.id,
|
|
44
|
+
poll_id: pollId,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -31,6 +31,10 @@ export const pollStateChangeValidators: Partial<
|
|
|
31
31
|
max_votes_allowed: ({ data, value }) => {
|
|
32
32
|
if (data.enforce_unique_vote && value)
|
|
33
33
|
return { max_votes_allowed: 'Enforce unique vote is enabled' };
|
|
34
|
+
const numericMatch = value.match(/^[0-9]+$/);
|
|
35
|
+
if (!numericMatch && value) {
|
|
36
|
+
return { max_votes_allowed: 'Only numbers are allowed' };
|
|
37
|
+
}
|
|
34
38
|
if (value?.length > 1 && !value.match(VALID_MAX_VOTES_VALUE_REGEX))
|
|
35
39
|
return { max_votes_allowed: 'Type a number from 2 to 10' };
|
|
36
40
|
return { max_votes_allowed: undefined };
|
|
@@ -225,7 +229,7 @@ export const createPollComposerStateMiddleware = ({
|
|
|
225
229
|
forward,
|
|
226
230
|
}: MiddlewareHandlerParams<PollComposerStateChangeMiddlewareValue>) => {
|
|
227
231
|
if (!state.targetFields) return forward();
|
|
228
|
-
const { previousState } = state;
|
|
232
|
+
const { previousState, injectedFieldErrors } = state;
|
|
229
233
|
const finalValidators = {
|
|
230
234
|
...pollStateChangeValidators,
|
|
231
235
|
...defaultPollFieldChangeEventValidators,
|
|
@@ -247,7 +251,7 @@ export const createPollComposerStateMiddleware = ({
|
|
|
247
251
|
nextState: {
|
|
248
252
|
...previousState,
|
|
249
253
|
data: { ...previousState.data, ...newData },
|
|
250
|
-
errors: { ...previousState.errors, ...newErrors },
|
|
254
|
+
errors: { ...previousState.errors, ...newErrors, ...injectedFieldErrors },
|
|
251
255
|
},
|
|
252
256
|
});
|
|
253
257
|
},
|
|
@@ -275,7 +279,11 @@ export const createPollComposerStateMiddleware = ({
|
|
|
275
279
|
nextState: {
|
|
276
280
|
...previousState,
|
|
277
281
|
data: { ...previousState.data, ...newData },
|
|
278
|
-
errors: {
|
|
282
|
+
errors: {
|
|
283
|
+
...previousState.errors,
|
|
284
|
+
...newErrors,
|
|
285
|
+
...state.injectedFieldErrors,
|
|
286
|
+
},
|
|
279
287
|
},
|
|
280
288
|
});
|
|
281
289
|
},
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createCommandsMiddleware } from './commands';
|
|
2
2
|
import { createMentionsMiddleware } from './mentions';
|
|
3
3
|
import { createTextComposerPreValidationMiddleware } from './validation';
|
|
4
|
+
import { MiddlewareExecutor } from '../../../middleware';
|
|
4
5
|
import type {
|
|
5
6
|
ExecuteParams,
|
|
6
7
|
MiddlewareExecutionResult,
|
|
7
8
|
MiddlewareHandler,
|
|
8
9
|
} from '../../../middleware';
|
|
9
|
-
import { MiddlewareExecutor } from '../../../middleware';
|
|
10
|
-
import { withCancellation } from '../../../utils/concurrency';
|
|
11
10
|
import type {
|
|
12
11
|
Suggestion,
|
|
12
|
+
Suggestions,
|
|
13
13
|
TextComposerMiddlewareExecutorOptions,
|
|
14
14
|
TextComposerState,
|
|
15
15
|
} from './types';
|
|
@@ -58,28 +58,14 @@ export class TextComposerMiddlewareExecutor<
|
|
|
58
58
|
initialValue: initialState,
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
);
|
|
71
|
-
if (searchResult === 'canceled') return { ...result, status: 'discard' };
|
|
72
|
-
} catch (error) {
|
|
73
|
-
// Clear suggestions on search error
|
|
74
|
-
return {
|
|
75
|
-
...result,
|
|
76
|
-
state: {
|
|
77
|
-
...result.state,
|
|
78
|
-
suggestions: undefined,
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
}
|
|
61
|
+
const { query, searchSource } = result.state.suggestions ?? ({} as Suggestions);
|
|
62
|
+
/**
|
|
63
|
+
* Catching error just for sanity purposes.
|
|
64
|
+
* The BaseSearchSource.search() method returns debounced result.
|
|
65
|
+
* That means the result of the previous search call as the debounced call result is unknown at the moment.
|
|
66
|
+
* Custom search source implementation should handle errors meaningfully internally.
|
|
67
|
+
*/
|
|
68
|
+
searchSource?.search(query)?.catch(console.error);
|
|
83
69
|
|
|
84
70
|
return result;
|
|
85
71
|
}
|
|
@@ -7,7 +7,11 @@ import { StateStore } from '../store';
|
|
|
7
7
|
import { VotingVisibility } from '../types';
|
|
8
8
|
import { generateUUIDv4 } from '../utils';
|
|
9
9
|
import type { MessageComposer } from './messageComposer';
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
PollComposerFieldErrors,
|
|
12
|
+
PollComposerState,
|
|
13
|
+
UpdateFieldsData,
|
|
14
|
+
} from './middleware/pollComposer';
|
|
11
15
|
|
|
12
16
|
export type PollComposerOptions = {
|
|
13
17
|
composer: MessageComposer;
|
|
@@ -102,13 +106,23 @@ export class PollComposer {
|
|
|
102
106
|
this.state.next(this.initialState);
|
|
103
107
|
};
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Updates specified fields and generates relevant errors
|
|
111
|
+
* @param data
|
|
112
|
+
* @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing
|
|
113
|
+
*/
|
|
114
|
+
// FIXME: change method params to a single object with the next major release
|
|
115
|
+
updateFields = async (
|
|
116
|
+
data: UpdateFieldsData,
|
|
117
|
+
injectedFieldErrors?: PollComposerFieldErrors,
|
|
118
|
+
) => {
|
|
106
119
|
const { state, status } = await this.stateMiddlewareExecutor.execute({
|
|
107
120
|
eventName: 'handleFieldChange',
|
|
108
121
|
initialValue: {
|
|
109
122
|
nextState: { ...this.state.getLatestValue() },
|
|
110
123
|
previousState: { ...this.state.getLatestValue() },
|
|
111
124
|
targetFields: data,
|
|
125
|
+
injectedFieldErrors,
|
|
112
126
|
},
|
|
113
127
|
});
|
|
114
128
|
|
package/src/types.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
CustomUserData,
|
|
18
18
|
} from './custom_types';
|
|
19
19
|
import type { NotificationManager } from './notifications';
|
|
20
|
+
import type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Utility Types
|
|
@@ -2945,23 +2946,7 @@ export type TranslationLanguages =
|
|
|
2945
2946
|
|
|
2946
2947
|
export type TypingStartEvent = Event;
|
|
2947
2948
|
|
|
2948
|
-
export type ReservedUpdatedMessageFields =
|
|
2949
|
-
| 'command'
|
|
2950
|
-
| 'created_at'
|
|
2951
|
-
| 'deleted_at'
|
|
2952
|
-
| 'html'
|
|
2953
|
-
| 'i18n'
|
|
2954
|
-
| 'latest_reactions'
|
|
2955
|
-
// the the original array of UserResponse object is converted to array of user ids and re-inserted before sending the update request
|
|
2956
|
-
| 'mentioned_users'
|
|
2957
|
-
| 'own_reactions'
|
|
2958
|
-
| 'pinned_at'
|
|
2959
|
-
| 'quoted_message'
|
|
2960
|
-
| 'reaction_counts'
|
|
2961
|
-
| 'reply_count'
|
|
2962
|
-
| 'type'
|
|
2963
|
-
| 'updated_at'
|
|
2964
|
-
| '__html';
|
|
2949
|
+
export type ReservedUpdatedMessageFields = keyof typeof RESERVED_UPDATED_MESSAGE_FIELDS;
|
|
2965
2950
|
|
|
2966
2951
|
export type UpdatedMessage = Omit<MessageResponse, ReservedUpdatedMessageFields> & {
|
|
2967
2952
|
mentioned_users?: string[];
|
package/src/utils.ts
CHANGED
|
@@ -367,14 +367,14 @@ export const localMessageToNewMessagePayload = (localMessage: LocalMessage): Mes
|
|
|
367
367
|
export const toUpdatedMessagePayload = (
|
|
368
368
|
message: LocalMessage | Partial<MessageResponse>,
|
|
369
369
|
): UpdatedMessage => {
|
|
370
|
+
const reservedKeys = {
|
|
371
|
+
...RESERVED_UPDATED_MESSAGE_FIELDS,
|
|
372
|
+
...LOCAL_MESSAGE_FIELDS,
|
|
373
|
+
} as const;
|
|
374
|
+
|
|
370
375
|
const messageFields = Object.fromEntries(
|
|
371
376
|
Object.entries(message).filter(
|
|
372
|
-
([key]) =>
|
|
373
|
-
![...RESERVED_UPDATED_MESSAGE_FIELDS, ...LOCAL_MESSAGE_FIELDS].includes(
|
|
374
|
-
key as
|
|
375
|
-
| (typeof RESERVED_UPDATED_MESSAGE_FIELDS)[number]
|
|
376
|
-
| (typeof LOCAL_MESSAGE_FIELDS)[number],
|
|
377
|
-
),
|
|
377
|
+
([key]) => !reservedKeys[key as keyof typeof reservedKeys],
|
|
378
378
|
),
|
|
379
379
|
) as UpdatedMessage;
|
|
380
380
|
|
|
@@ -384,7 +384,6 @@ export const toUpdatedMessagePayload = (
|
|
|
384
384
|
mentioned_users: message.mentioned_users?.map((user) =>
|
|
385
385
|
typeof user === 'string' ? user : user.id,
|
|
386
386
|
),
|
|
387
|
-
user_id: message.user?.id ?? message.user_id,
|
|
388
387
|
};
|
|
389
388
|
};
|
|
390
389
|
|