Skip to content

Commit e818e43

Browse files
chohongmAhyoungRyuHoonBaek
authored
Merge v3.14.0-beta-1 to main! (#1044)
## [v3.14.0] (Apr 5, 2024) ### Feature - `TemplateMessageItemBody` now supports `CarouselView` type template - Added 'wide' width support for `MessageContent` when value exists in `message.extendedMessagePayload['ui']['container_type']` - Added template version validation for `TemplateMessageItemBody` ### Message template fixes/updates - Fixed a bug where argb color values are not converted to rgba - Fixed a bug where style properties expecting numeric values are set with string values - Removed default values of `borderRadius`, `backgroundColor`, and `color` for message template items ### Other fixes - Fixed a bug where scroll bar is displayed in message sender name container --------- Co-authored-by: Ahyoung Ryu <irene.ryu@sendbird.com> Co-authored-by: Baek EunSeo <hoon@sendbird.com>
1 parent 92db53d commit e818e43

File tree

36 files changed

+1036
-317
lines changed

36 files changed

+1036
-317
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Changelog - v3
22

3+
## [v3.14.0] (Apr 5, 2024)
4+
### Feature
5+
- `TemplateMessageItemBody` now supports `CarouselView` type template
6+
- Added 'wide' width support for `MessageContent` when value exists in `message.extendedMessagePayload['ui']['container_type']`
7+
- Added template version validation for `TemplateMessageItemBody`
8+
9+
### Message template fixes/updates
10+
- Fixed a bug where argb color values are not converted to rgba
11+
- Fixed a bug where style properties expecting numeric values are set with string values
12+
- Removed default values of `borderRadius`, `backgroundColor`, and `color` for message template items
13+
14+
### Other fixes
15+
- Fixed a bug where scroll bar is displayed in message sender name container
16+
317
## [v3.13.5] (Apr 5, 2024)
418

519
### Fixes

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@
6767
"react-dom": "^16.8.6 || ^17.0.0 || ^18.0.0"
6868
},
6969
"dependencies": {
70-
"@sendbird/chat": "^4.11.0",
71-
"@sendbird/react-uikit-message-template-view": "0.0.1-alpha.68",
72-
"@sendbird/uikit-tools": "0.0.1-alpha.68",
70+
"@sendbird/chat": "^4.11.3",
71+
"@sendbird/react-uikit-message-template-view": "0.0.1-alpha.72",
72+
"@sendbird/uikit-tools": "0.0.1-alpha.72",
7373
"css-vars-ponyfill": "^2.3.2",
7474
"date-fns": "^2.16.1",
7575
"dompurify": "^3.0.1"

scripts/steps.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
- Add all merged [SBISSUES tickets](https://sendbird.atlassian.net/jira/dashboards/11202?maximized=25045) in the `Linked issues` as `blocks` (When the ticket status changes to `Released`, Atlassan automatically adds a comment to each linked issues).
3535
8. Ask EM to review the release ticket and await for `Release approved`.
3636
9. In the root, `yarn build` to create new build files. Once created, make sure files in `dist` is newly created/updated.
37-
10. Change directory to `./dist` and then publish `npm publish`
37+
10. Change directory to `./dist` and then publish `npm publish` (`npm publish --tag beta` for beta release).
3838
11. In the release branch, create a new tag `v{X.X.X}` and the push the tag `git push v{X.X.X} origin`.
3939
12. After release do the followings:
4040
- Update release ticket to `Released`

src/lib/dux/appInfo/actionTypes.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { MessageTemplatesInfo, ProcessedMessageTemplate } from './initialState';
33

44
export const APP_INFO_ACTIONS = {
55
INITIALIZE_MESSAGE_TEMPLATES_INFO: 'INITIALIZE_MESSAGE_TEMPLATES_INFO',
6-
UPSERT_MESSAGE_TEMPLATE: 'UPSERT_MESSAGE_TEMPLATE',
7-
UPSERT_WAITING_TEMPLATE_KEY: 'UPSERT_WAITING_TEMPLATE_KEY',
8-
MARK_ERROR_WAITING_TEMPLATE_KEY: 'MARK_ERROR_WAITING_TEMPLATE_KEY',
6+
UPSERT_MESSAGE_TEMPLATES: 'UPSERT_MESSAGE_TEMPLATES',
7+
UPSERT_WAITING_TEMPLATE_KEYS: 'UPSERT_WAITING_TEMPLATE_KEYS',
8+
MARK_ERROR_WAITING_TEMPLATE_KEYS: 'MARK_ERROR_WAITING_TEMPLATE_KEYS',
99
} as const;
1010

1111
export type TemplatesMapData = {
@@ -15,9 +15,9 @@ export type TemplatesMapData = {
1515

1616
type APP_INFO_PAYLOAD_TYPES = {
1717
[APP_INFO_ACTIONS.INITIALIZE_MESSAGE_TEMPLATES_INFO]: MessageTemplatesInfo,
18-
[APP_INFO_ACTIONS.UPSERT_MESSAGE_TEMPLATE]: TemplatesMapData,
19-
[APP_INFO_ACTIONS.UPSERT_WAITING_TEMPLATE_KEY]: { key: string, requestedAt: number },
20-
[APP_INFO_ACTIONS.MARK_ERROR_WAITING_TEMPLATE_KEY]: { key: string },
18+
[APP_INFO_ACTIONS.UPSERT_MESSAGE_TEMPLATES]: TemplatesMapData[],
19+
[APP_INFO_ACTIONS.UPSERT_WAITING_TEMPLATE_KEYS]: { keys: string[], requestedAt: number },
20+
[APP_INFO_ACTIONS.MARK_ERROR_WAITING_TEMPLATE_KEYS]: { keys: string[], messageId: number },
2121
};
2222

2323
export type AppInfoActionTypes = CreateAction<APP_INFO_PAYLOAD_TYPES>;

src/lib/dux/appInfo/initialState.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export type ProcessedMessageTemplate = {
2-
uiTemplate: string; // This is stringified ui_template.
2+
version: number;
3+
uiTemplate: string; // This is stringified ui_template.body.items
34
colorVariables?: Record<string, string>;
45
};
56

@@ -10,7 +11,7 @@ export interface MessageTemplatesInfo {
1011

1112
export interface WaitingTemplateKeyData {
1213
requestedAt: number;
13-
isError: boolean;
14+
erroredMessageIds: number[];
1415
}
1516

1617
export interface AppInfoStateType {

src/lib/dux/appInfo/reducers.ts

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,54 @@ export default function reducer(state: AppInfoStateType, action: AppInfoActionTy
1313
};
1414
})
1515
.with(
16-
{ type: APP_INFO_ACTIONS.UPSERT_MESSAGE_TEMPLATE },
16+
{ type: APP_INFO_ACTIONS.UPSERT_MESSAGE_TEMPLATES },
1717
({ payload }) => {
1818
const templatesInfo = state.messageTemplatesInfo;
1919
if (!templatesInfo) return state; // Not initialized. Ignore.
2020

21-
const { key, template } = payload;
22-
templatesInfo.templatesMap[key] = template;
23-
24-
delete state.waitingTemplateKeysMap[key];
25-
21+
const waitingTemplateKeysMap = { ...state.waitingTemplateKeysMap };
22+
payload.forEach((templatesMapData) => {
23+
const { key, template } = templatesMapData;
24+
templatesInfo.templatesMap[key] = template;
25+
delete waitingTemplateKeysMap[key];
26+
});
2627
return {
2728
...state,
29+
waitingTemplateKeysMap,
2830
messageTemplatesInfo: templatesInfo,
2931
};
3032
})
3133
.with(
32-
{ type: APP_INFO_ACTIONS.UPSERT_WAITING_TEMPLATE_KEY },
34+
{ type: APP_INFO_ACTIONS.UPSERT_WAITING_TEMPLATE_KEYS },
3335
({ payload }) => {
34-
const { key, requestedAt } = payload;
35-
state.waitingTemplateKeysMap[key] = {
36-
requestedAt,
37-
isError: false,
36+
const { keys, requestedAt } = payload;
37+
const waitingTemplateKeysMap = { ...state.waitingTemplateKeysMap };
38+
keys.forEach((key) => {
39+
waitingTemplateKeysMap[key] = {
40+
erroredMessageIds: waitingTemplateKeysMap[key]?.erroredMessageIds ?? [],
41+
requestedAt,
42+
};
43+
});
44+
return {
45+
...state,
46+
waitingTemplateKeysMap,
3847
};
39-
return { ...state };
4048
})
4149
.with(
42-
{ type: APP_INFO_ACTIONS.MARK_ERROR_WAITING_TEMPLATE_KEY },
50+
{ type: APP_INFO_ACTIONS.MARK_ERROR_WAITING_TEMPLATE_KEYS },
4351
({ payload }) => {
44-
const { key } = payload;
45-
const waitingTemplateKeyData: WaitingTemplateKeyData | undefined = state.waitingTemplateKeysMap[key];
46-
if (waitingTemplateKeyData) {
47-
waitingTemplateKeyData.isError = true;
48-
}
49-
return { ...state };
52+
const { keys, messageId } = payload;
53+
const waitingTemplateKeysMap = { ...state.waitingTemplateKeysMap };
54+
keys.forEach((key) => {
55+
const waitingTemplateKeyData: WaitingTemplateKeyData | undefined = waitingTemplateKeysMap[key];
56+
if (waitingTemplateKeyData && waitingTemplateKeyData.erroredMessageIds.indexOf(messageId) === -1) {
57+
waitingTemplateKeyData.erroredMessageIds.push(messageId);
58+
}
59+
});
60+
return {
61+
...state,
62+
waitingTemplateKeysMap,
63+
};
5064
})
5165
.otherwise(() => {
5266
return state;

src/lib/dux/appInfo/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { SendbirdMessageTemplate } from '../../../ui/TemplateMessageItemBody/typ
66
*/
77
export const getProcessedTemplate = (parsedTemplate: SendbirdMessageTemplate): ProcessedMessageTemplate => {
88
return {
9+
version: Number(parsedTemplate.ui_template.version),
910
uiTemplate: JSON.stringify(parsedTemplate.ui_template.body.items),
1011
colorVariables: parsedTemplate.color_variables,
1112
};
1213
};
1314

14-
export const getProcessedTemplates = (
15+
export const getProcessedTemplatesMap = (
1516
parsedTemplates: SendbirdMessageTemplate[],
1617
): Record<string, ProcessedMessageTemplate> => {
1718
const processedTemplates = {};

src/lib/hooks/useMessageTemplateUtils.ts

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { AppInfoStateType, MessageTemplatesInfo, ProcessedMessageTemplate } from '../dux/appInfo/initialState';
33
import { SendbirdMessageTemplate } from '../../ui/TemplateMessageItemBody/types';
4-
import { getProcessedTemplate, getProcessedTemplates } from '../dux/appInfo/utils';
4+
import { getProcessedTemplate, getProcessedTemplatesMap } from '../dux/appInfo/utils';
55
import SendbirdChat from '@sendbird/chat';
66
import { APP_INFO_ACTIONS, AppInfoActionTypes } from '../dux/appInfo/actionTypes';
77
import { CACHED_MESSAGE_TEMPLATES_KEY, CACHED_MESSAGE_TEMPLATES_TOKEN_KEY } from '../../utils/consts';
@@ -18,15 +18,15 @@ interface UseMessageTemplateUtilsProps {
1818

1919
export interface UseMessageTemplateUtilsWrapper {
2020
getCachedTemplate: (key: string) => ProcessedMessageTemplate | null;
21-
updateMessageTemplatesInfo: (templateKey: string, requestedAt: number) => Promise<void>;
21+
updateMessageTemplatesInfo: (templateKeys: string[], messageId: number, requestedAt: number) => Promise<void>;
2222
initializeMessageTemplatesInfo: (readySdk: SendbirdChat) => Promise<void>;
2323
}
2424

2525
const {
2626
INITIALIZE_MESSAGE_TEMPLATES_INFO,
27-
UPSERT_MESSAGE_TEMPLATE,
28-
UPSERT_WAITING_TEMPLATE_KEY,
29-
MARK_ERROR_WAITING_TEMPLATE_KEY,
27+
UPSERT_MESSAGE_TEMPLATES,
28+
UPSERT_WAITING_TEMPLATE_KEYS,
29+
MARK_ERROR_WAITING_TEMPLATE_KEYS,
3030
} = APP_INFO_ACTIONS;
3131

3232
export default function useMessageTemplateUtils({
@@ -105,7 +105,7 @@ export default function useMessageTemplateUtils({
105105
const parsedTemplates = await fetchAllMessageTemplates(readySdk);
106106
const newMessageTemplatesInfo: MessageTemplatesInfo = {
107107
token: sdkMessageTemplateToken,
108-
templatesMap: getProcessedTemplates(parsedTemplates),
108+
templatesMap: getProcessedTemplatesMap(parsedTemplates),
109109
};
110110
appInfoDispatcher({ type: INITIALIZE_MESSAGE_TEMPLATES_INFO, payload: newMessageTemplatesInfo });
111111
localStorage.setItem(CACHED_MESSAGE_TEMPLATES_TOKEN_KEY, sdkMessageTemplateToken);
@@ -118,7 +118,7 @@ export default function useMessageTemplateUtils({
118118
const parsedTemplates: SendbirdMessageTemplate[] = JSON.parse(cachedMessageTemplates);
119119
const newMessageTemplatesInfo: MessageTemplatesInfo = {
120120
token: sdkMessageTemplateToken,
121-
templatesMap: getProcessedTemplates(parsedTemplates),
121+
templatesMap: getProcessedTemplatesMap(parsedTemplates),
122122
};
123123
appInfoDispatcher({ type: INITIALIZE_MESSAGE_TEMPLATES_INFO, payload: newMessageTemplatesInfo });
124124
}
@@ -128,54 +128,72 @@ export default function useMessageTemplateUtils({
128128
* If given message is a template message with template key and if the key does not exist in the cache,
129129
* update the cache by fetching the template.
130130
*/
131-
const updateMessageTemplatesInfo = async (templateKey: string, requestedAt: number): Promise<void> => {
131+
const updateMessageTemplatesInfo = async (
132+
templateKeys: string[],
133+
messageId: number,
134+
requestedAt: number,
135+
): Promise<void> => {
132136
if (appInfoDispatcher) {
133137
appInfoDispatcher({
134-
type: UPSERT_WAITING_TEMPLATE_KEY,
138+
type: UPSERT_WAITING_TEMPLATE_KEYS,
135139
payload: {
136-
key: templateKey,
140+
keys: templateKeys,
137141
requestedAt,
138142
},
139143
});
140-
141-
let parsedTemplate: SendbirdMessageTemplate | null = null;
144+
const newParsedTemplates: SendbirdMessageTemplate[] | null = [];
142145
try {
143-
const newTemplate = await sdk.message.getMessageTemplate(templateKey);
144-
parsedTemplate = JSON.parse(newTemplate.template);
146+
let hasMore = true;
147+
let token = null;
148+
while (hasMore) {
149+
const result = await sdk.message.getMessageTemplatesByToken(token, {
150+
keys: templateKeys,
151+
});
152+
result.templates.forEach((newTemplate) => {
153+
newParsedTemplates.push(JSON.parse(newTemplate.template));
154+
});
155+
hasMore = result.hasMore;
156+
token = result.token;
157+
}
145158
} catch (e) {
146-
logger?.error?.('Sendbird | fetchProcessedMessageTemplate failed', e);
159+
logger?.error?.('Sendbird | fetchProcessedMessageTemplates failed', e, templateKeys);
147160
}
148-
149-
if (parsedTemplate) {
161+
if (newParsedTemplates.length > 0) {
150162
// Update cache
151163
const cachedMessageTemplates: string | null = localStorage.getItem(CACHED_MESSAGE_TEMPLATES_KEY);
152164
if (cachedMessageTemplates) {
153165
const parsedTemplates: SendbirdMessageTemplate[] = JSON.parse(cachedMessageTemplates);
154-
parsedTemplates.push(parsedTemplate);
166+
const existingKeys = parsedTemplates.map((parsedTemplate) => parsedTemplate.key);
167+
newParsedTemplates.forEach((newParsedTemplate) => {
168+
if (!existingKeys.includes(newParsedTemplate.key)) {
169+
parsedTemplates.push(newParsedTemplate);
170+
}
171+
});
155172
localStorage.setItem(CACHED_MESSAGE_TEMPLATES_KEY, JSON.stringify(parsedTemplates));
156173
} else {
157-
localStorage.setItem(CACHED_MESSAGE_TEMPLATES_KEY, JSON.stringify([parsedTemplate]));
174+
localStorage.setItem(CACHED_MESSAGE_TEMPLATES_KEY, JSON.stringify([newParsedTemplates]));
158175
}
159176
// Update memory
160-
const processedTemplate: ProcessedMessageTemplate = getProcessedTemplate(parsedTemplate);
161177
appInfoDispatcher({
162-
type: UPSERT_MESSAGE_TEMPLATE,
163-
payload: {
164-
key: templateKey,
165-
template: processedTemplate,
166-
},
178+
type: UPSERT_MESSAGE_TEMPLATES,
179+
payload: newParsedTemplates.map((newParsedTemplate) => {
180+
return {
181+
key: newParsedTemplate.key,
182+
template: getProcessedTemplate(newParsedTemplate),
183+
};
184+
}),
167185
});
168186
} else {
169187
appInfoDispatcher({
170-
type: MARK_ERROR_WAITING_TEMPLATE_KEY,
188+
type: MARK_ERROR_WAITING_TEMPLATE_KEYS,
171189
payload: {
172-
key: templateKey,
190+
keys: templateKeys,
191+
messageId,
173192
},
174193
});
175194
}
176195
}
177196
};
178-
179197
return {
180198
getCachedTemplate,
181199
updateMessageTemplatesInfo,

src/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,6 @@ export type SendbirdChatInitParams = Omit<SendbirdChatParams<Module[]>, 'appId'>
258258
export type CustomExtensionParams = Record<string, string>;
259259

260260
export type SendbirdProviderUtils = {
261-
updateMessageTemplatesInfo: (templateKey: string, createdAt: number) => Promise<void>;
261+
updateMessageTemplatesInfo: (templateKeys: string[], messageId: number, createdAt: number) => Promise<void>;
262262
getCachedTemplate: (key: string) => ProcessedMessageTemplate | null;
263263
};

src/modules/GroupChannel/components/MessageList/index.scss

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@
88
position: relative;
99
.sendbird-conversation__messages-padding {
1010
position: relative;
11-
padding-left: 24px;
12-
padding-right: 24px;
1311
height: 100%;
1412
overflow-x: hidden;
15-
overflow-y: scroll;
1613
}
1714
.sendbird-separator,
1815
.sendbird-admin-message {

0 commit comments

Comments
 (0)