diff --git a/app/containers/UIKit/MultiSelect/Chips.tsx b/app/containers/UIKit/MultiSelect/Chips.tsx
index 30584885c..ac10c932d 100644
--- a/app/containers/UIKit/MultiSelect/Chips.tsx
+++ b/app/containers/UIKit/MultiSelect/Chips.tsx
@@ -31,6 +31,7 @@ const Chip = ({ item, onSelect, style }: IChip) => {
onPress={() => onSelect(item)}
style={[styles.chip, { backgroundColor: colors.auxiliaryBackground }, style]}
background={Touchable.Ripple(colors.bannerBackground)}
+ testID={`multi-select-chip-${item.value}`}
>
<>
{item.imageUrl ? : null}
diff --git a/app/containers/UIKit/MultiSelect/Items.tsx b/app/containers/UIKit/MultiSelect/Items.tsx
index 8c8b07c1e..9f8f9cf26 100644
--- a/app/containers/UIKit/MultiSelect/Items.tsx
+++ b/app/containers/UIKit/MultiSelect/Items.tsx
@@ -13,13 +13,13 @@ import { CustomIcon } from '../../CustomIcon';
interface IItem {
item: IItemData;
- selected?: string;
+ selected: boolean;
onSelect: Function;
}
interface IItems {
items: IItemData[];
- selected: string[];
+ selected: IItemData[];
onSelect: Function;
}
@@ -54,7 +54,7 @@ const Items = ({ items, selected, onSelect }: IItems) => (
keyboardShouldPersistTaps='always'
ItemSeparatorComponent={List.Separator}
keyExtractor={keyExtractor}
- renderItem={({ item }) => - s === item.value)} />}
+ renderItem={({ item }) =>
- s.value === item.value)} />}
/>
);
diff --git a/app/containers/UIKit/MultiSelect/MultiSelectContent.tsx b/app/containers/UIKit/MultiSelect/MultiSelectContent.tsx
index 9a9bd632b..270163692 100644
--- a/app/containers/UIKit/MultiSelect/MultiSelectContent.tsx
+++ b/app/containers/UIKit/MultiSelect/MultiSelectContent.tsx
@@ -17,16 +17,16 @@ interface IMultiSelectContentProps {
options?: IItemData[];
multiselect: boolean;
select: React.Dispatch;
- onChange: Function;
+ onChange: ({ value }: { value: string[] }) => void;
setCurrentValue: React.Dispatch>;
onHide: Function;
- selectedItems: string[];
+ selectedItems: IItemData[];
}
export const MultiSelectContent = React.memo(
({ onSearch, options, multiselect, select, onChange, setCurrentValue, onHide, selectedItems }: IMultiSelectContentProps) => {
const { colors } = useTheme();
- const [selected, setSelected] = useState(Array.isArray(selectedItems) ? selectedItems : []);
+ const [selected, setSelected] = useState(Array.isArray(selectedItems) ? selectedItems : []);
const [items, setItems] = useState(options);
const { hideActionSheet } = useActionSheet();
@@ -37,14 +37,14 @@ export const MultiSelectContent = React.memo(
} = item;
if (multiselect) {
let newSelect = [];
- if (!selected.includes(value)) {
- newSelect = [...selected, value];
+ if (!selected.find(s => s.value === value)) {
+ newSelect = [...selected, item];
} else {
- newSelect = selected.filter((s: any) => s !== value);
+ newSelect = selected.filter((s: any) => s.value !== value);
}
setSelected(newSelect);
select(newSelect);
- onChange({ value: newSelect });
+ onChange({ value: newSelect.map(s => s.value) });
} else {
onChange({ value });
setCurrentValue(text);
diff --git a/app/containers/UIKit/MultiSelect/index.tsx b/app/containers/UIKit/MultiSelect/index.tsx
index 20e9e0975..7808683a0 100644
--- a/app/containers/UIKit/MultiSelect/index.tsx
+++ b/app/containers/UIKit/MultiSelect/index.tsx
@@ -17,13 +17,21 @@ export interface IItemData {
imageUrl?: string;
}
+interface IMultiSelectWithMultiSelect extends IMultiSelect {
+ multiselect: true;
+ onChange: ({ value }: { value: string[] }) => void;
+}
+
+interface IMultiSelectWithoutMultiSelect extends IMultiSelect {
+ multiselect?: false;
+ onChange: ({ value }: { value: any }) => void;
+}
+
interface IMultiSelect {
options?: IItemData[];
- onChange: Function;
placeholder?: IText;
context?: BlockContext;
loading?: boolean;
- multiselect?: boolean;
onSearch?: (keyword: string) => IItemData[] | Promise;
onClose?: () => void;
inputStyle?: TextStyle;
@@ -46,9 +54,9 @@ export const MultiSelect = React.memo(
disabled,
inputStyle,
innerInputStyle
- }: IMultiSelect) => {
+ }: IMultiSelectWithMultiSelect | IMultiSelectWithoutMultiSelect) => {
const { colors } = useTheme();
- const [selected, select] = useState(Array.isArray(values) ? values : []);
+ const [selected, select] = useState(Array.isArray(values) ? values : []);
const [currentValue, setCurrentValue] = useState('');
const { showActionSheet, hideActionSheet } = useActionSheet();
@@ -57,7 +65,7 @@ export const MultiSelect = React.memo(
if (Array.isArray(values)) {
select(values);
}
- }, [values]);
+ }, []);
useEffect(() => {
if (values && values.length && !multiselect) {
@@ -95,13 +103,13 @@ export const MultiSelect = React.memo(
} = item;
if (multiselect) {
let newSelect = [];
- if (!selected.includes(value)) {
- newSelect = [...selected, value];
+ if (!selected.find(s => s.value === value)) {
+ newSelect = [...selected, item];
} else {
- newSelect = selected.filter((s: any) => s !== value);
+ newSelect = selected.filter((s: any) => s.value !== value);
}
select(newSelect);
- onChange({ value: newSelect });
+ onChange({ value: newSelect.map(s => s.value) });
} else {
onChange({ value });
setCurrentValue(text);
@@ -119,12 +127,10 @@ export const MultiSelect = React.memo(
);
if (context === BlockContext.FORM) {
- const items: any = options.filter((option: any) => selected.includes(option.value));
-
button = (
- {items.length ? (
- (disabled ? {} : onSelect(item))} />
+ {selected.length ? (
+ (disabled ? {} : onSelect(item))} />
) : (
{placeholder.text}
)}
diff --git a/app/containers/UIKit/UiKitMessage.stories.tsx b/app/containers/UIKit/UiKitMessage.stories.tsx
index ecb5d7bcd..696732047 100644
--- a/app/containers/UIKit/UiKitMessage.stories.tsx
+++ b/app/containers/UIKit/UiKitMessage.stories.tsx
@@ -220,36 +220,37 @@ export const SectionMultiSelect = () =>
},
accessory: {
type: 'multi_static_select',
+ appId: 'app-id',
+ blockId: 'block-id',
+ actionId: 'action-id',
+ initialValue: ['option_1', 'option_2'],
options: [
{
+ value: 'option_1',
text: {
type: 'plain_text',
- text: 'button'
- },
- value: 1
+ text: 'lorem ipsum 🚀',
+ emoji: true
+ }
},
{
+ value: 'option_2',
text: {
type: 'plain_text',
- text: 'opt 1'
- },
- value: 2
- },
- {
- text: {
- type: 'plain_text',
- text: 'opt 2'
- },
- value: 3
- },
- {
- text: {
- type: 'plain_text',
- text: 'opt 3'
- },
- value: 4
+ text: 'lorem ipsum 🚀',
+ emoji: true
+ }
}
- ]
+ ],
+ placeholder: {
+ type: 'plain_text',
+ text: 'Select an item'
+ },
+ label: {
+ type: 'plain_text',
+ text: 'Label',
+ emoji: true
+ }
}
}
]);
diff --git a/app/containers/UIKit/index.tsx b/app/containers/UIKit/index.tsx
index 6dbd87f28..d03efec1c 100644
--- a/app/containers/UIKit/index.tsx
+++ b/app/containers/UIKit/index.tsx
@@ -138,7 +138,8 @@ class MessageParser extends UiKitParserMessage {
multiStaticSelect(element: IElement, context: BlockContext) {
const [{ loading, value }, action] = useBlockContext(element, context);
- return ;
+ const valueFiltered = element.options?.filter(option => value.includes(option.value));
+ return ;
}
staticSelect(element: IElement, context: BlockContext) {
diff --git a/app/views/CreateDiscussionView/interfaces.ts b/app/views/CreateDiscussionView/interfaces.ts
index f80b2b3c5..47163cfb3 100644
--- a/app/views/CreateDiscussionView/interfaces.ts
+++ b/app/views/CreateDiscussionView/interfaces.ts
@@ -39,7 +39,7 @@ export interface ICreateDiscussionViewSelectChannel {
token: string;
userId: string;
initial: object;
- onChannelSelect: Function;
+ onChannelSelect: ({ value }: { value: any }) => void;
blockUnauthenticatedAccess: boolean;
serverVersion: string;
}
@@ -49,7 +49,7 @@ export interface ICreateDiscussionViewSelectUsers {
token: string;
userId: string;
selected: any[];
- onUserSelect: Function;
+ onUserSelect: ({ value }: { value: string[] }) => void;
blockUnauthenticatedAccess: boolean;
serverVersion: string;
}
diff --git a/app/views/LivechatEditView.tsx b/app/views/LivechatEditView.tsx
index f06c7eca3..aad596a01 100644
--- a/app/views/LivechatEditView.tsx
+++ b/app/views/LivechatEditView.tsx
@@ -90,6 +90,11 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
const [tagParam, setTags] = useState(livechat?.tags || []);
const [tagParamSelected, setTagParamSelected] = useState(livechat?.tags || []);
+ const tagOptions = tagParam.map((tag: string) => ({ text: { text: tag }, value: tag }));
+ const tagValues = Array.isArray(tagParamSelected)
+ ? tagOptions.filter((option: any) => tagParamSelected.includes(option.value))
+ : [];
+
useEffect(() => {
const arr = [...tagParam, ...availableUserTags];
const uniqueArray = arr.filter((val, i) => arr.indexOf(val) === i);
@@ -254,12 +259,12 @@ const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewP
{I18n.t('Tags')}
({ text: { text: tag }, value: tag }))}
+ options={tagOptions}
onChange={({ value }: { value: string[] }) => {
setTagParamSelected([...value]);
}}
placeholder={{ text: I18n.t('Tags') }}
- value={tagParamSelected}
+ value={tagValues}
context={BlockContext.FORM}
multiselect
disabled={!editLivechatRoomCustomFieldsPermission}
diff --git a/app/views/RoomInfoEditView/index.tsx b/app/views/RoomInfoEditView/index.tsx
index 93e54630f..2132a382e 100644
--- a/app/views/RoomInfoEditView/index.tsx
+++ b/app/views/RoomInfoEditView/index.tsx
@@ -78,6 +78,11 @@ interface IRoomInfoEditViewProps extends IBaseScreen ({
+ value: m.value,
+ text: { text: I18n.t('Hide_type_messages', { type: I18n.t(m.text) }) }
+}));
+
class RoomInfoEditView extends React.Component {
randomValue = random(15);
private querySubscription: Subscription | undefined;
@@ -447,15 +452,16 @@ class RoomInfoEditView extends React.Component systemMessages.includes(option.value))
+ : [];
+
return (
({
- value: m.value,
- text: { text: I18n.t('Hide_type_messages', { type: I18n.t(m.text) }) }
- }))}
- onChange={({ value }: { value: boolean }) => this.setState({ systemMessages: value })}
+ options={MESSAGE_TYPE_VALUES}
+ onChange={({ value }) => this.setState({ systemMessages: value })}
placeholder={{ text: I18n.t('Hide_System_Messages') }}
- value={systemMessages as string[]}
+ value={values}
context={BlockContext.FORM}
multiselect
/>
diff --git a/e2e/tests/room/04-discussion.spec.ts b/e2e/tests/room/04-discussion.spec.ts
index 434316739..5360ab693 100644
--- a/e2e/tests/room/04-discussion.spec.ts
+++ b/e2e/tests/room/04-discussion.spec.ts
@@ -31,6 +31,7 @@ describe('Discussion', () => {
});
it('should create discussion from NewMessageView', async () => {
+ const selectUser = 'rocket.cat';
await waitFor(element(by.id('rooms-list-view-create-channel')))
.toExist()
.withTimeout(2000);
@@ -53,6 +54,30 @@ describe('Discussion', () => {
.withTimeout(10000);
await element(by.id(`multi-select-item-${room}`)).tap();
await element(by.id('multi-select-discussion-name')).replaceText(discussionFromNewMessage);
+ await element(by[textMatcher]('Select users...')).tap();
+ await element(by.id('multi-select-search')).replaceText(`${selectUser}`);
+ await waitFor(element(by.id(`multi-select-item-${selectUser}`)))
+ .toExist()
+ .withTimeout(10000);
+ await element(by.id(`multi-select-item-${selectUser}`)).tap();
+ await sleep(300);
+ // checking if the chip was placed properly
+ await waitFor(element(by.id(`multi-select-chip-${selectUser}`)))
+ .toExist()
+ .withTimeout(10000);
+ // should keep the same chip even when the user does a new research
+ await element(by.id('multi-select-search')).replaceText(`user`);
+ await waitFor(element(by.id(`multi-select-item-${selectUser}`)))
+ .not.toExist()
+ .withTimeout(10000);
+ await waitFor(element(by.id(`multi-select-chip-${selectUser}`)))
+ .toExist()
+ .withTimeout(10000);
+ await sleep(500);
+ await element(by.id('multi-select-search')).tapReturnKey();
+ await sleep(500);
+ // removing the rocket.cat from the users
+ await element(by.id(`multi-select-chip-${selectUser}`)).tap();
await waitFor(element(by.id('create-discussion-submit')))
.toExist()
.withTimeout(10000);