Rocket.Chat.ReactNative/app/containers/UIKit/MultiSelect/index.js

206 lines
5.0 KiB
JavaScript
Raw Normal View History

2020-02-11 14:01:35 +00:00
import React, { useState, useEffect } from 'react';
import {
View, Text, TouchableWithoutFeedback, Modal, KeyboardAvoidingView, Animated, Easing, StyleSheet
2020-02-11 14:01:35 +00:00
} from 'react-native';
import PropTypes from 'prop-types';
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
import Button from '../../Button';
import TextInput from '../../TextInput';
import { textParser } from '../utils';
import { themes } from '../../../constants/colors';
import I18n from '../../../i18n';
import { isIOS } from '../../../utils/deviceInfo';
2020-02-11 14:01:35 +00:00
import Chips from './Chips';
import Items from './Items';
import Input from './Input';
import styles from './styles';
const ANIMATION_DURATION = 200;
const ANIMATION_PROPS = {
duration: ANIMATION_DURATION,
easing: Easing.inOut(Easing.quad),
useNativeDriver: true
};
const animatedValue = new Animated.Value(0);
const behavior = isIOS ? 'padding' : null;
2020-02-11 14:01:35 +00:00
export const MultiSelect = React.memo(({
options = [],
onChange,
placeholder = { text: 'Search' },
context,
loading,
value: values,
multiselect = false,
onSearch,
onClose,
disabled,
inputStyle,
2020-02-11 14:01:35 +00:00
theme
}) => {
const [selected, select] = useState(Array.isArray(values) ? values : []);
2020-02-11 14:01:35 +00:00
const [open, setOpen] = useState(false);
const [search, onSearchChange] = useState('');
const [currentValue, setCurrentValue] = useState('');
const [showContent, setShowContent] = useState(false);
useEffect(() => {
if (Array.isArray(values)) {
select(values);
}
}, [values]);
2020-02-11 14:01:35 +00:00
useEffect(() => {
setOpen(showContent);
}, [showContent]);
useEffect(() => {
if (values && values.length && !multiselect) {
setCurrentValue(values[0].text);
}
}, []);
2020-02-11 14:01:35 +00:00
const onShow = () => {
Animated.timing(
animatedValue,
{
toValue: 1,
...ANIMATION_PROPS
}
).start();
setShowContent(true);
};
const onHide = () => {
onClose();
2020-02-11 14:01:35 +00:00
Animated.timing(
animatedValue,
{
toValue: 0,
...ANIMATION_PROPS
}
).start(() => setShowContent(false));
};
const onSelect = (item) => {
const { value, text: { text } } = item;
2020-02-11 14:01:35 +00:00
if (multiselect) {
let newSelect = [];
if (!selected.includes(value)) {
newSelect = [...selected, value];
} else {
newSelect = selected.filter(s => s !== value);
}
select(newSelect);
onChange({ value: newSelect });
} else {
onChange({ value });
setCurrentValue(text);
onHide();
2020-02-11 14:01:35 +00:00
}
};
const renderContent = () => {
const items = onSearch ? options : options.filter(option => textParser([option.text]).toLowerCase().includes(search.toLowerCase()));
2020-02-11 14:01:35 +00:00
return (
<View style={[styles.modal, { backgroundColor: themes[theme].backgroundColor }]}>
<View style={[styles.content, { backgroundColor: themes[theme].backgroundColor }]}>
<TextInput
testID='multi-select-search'
onChangeText={onSearch || onSearchChange}
placeholder={I18n.t('Search')}
2020-02-11 14:01:35 +00:00
theme={theme}
/>
<Items items={items} selected={selected} onSelect={onSelect} theme={theme} />
</View>
</View>
);
};
const translateY = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [600, 0]
});
let button = multiselect ? (
<Button
title={`${ selected.length } selecteds`}
onPress={onShow}
loading={loading}
theme={theme}
/>
) : (
<Input
[NEW] Livechat (#2004) * [WIP][NEW] Livechat info/actions * [IMPROVEMENT] RoomActionsView * [NEW] Visitor Navigation * [NEW] Get Department REST * [FIX] Borders * [IMPROVEMENT] Refactor RoomInfo View * [FIX] Error while navigate from mention -> roomInfo * [NEW] Livechat Fields * [NEW] Close Livechat * [WIP] Forward livechat * [NEW] Return inquiry * [WIP] Comment when close livechat * [WIP] Improve roomInfo * [IMPROVEMENT] Forward room * [FIX] Department picker * [FIX] Picker without results * [FIX] Superfluous argument * [FIX] Check permissions on RoomActionsView * [FIX] Livechat permissions * [WIP] Show edit to livechat * [I18N] Add pt-br translations * [WIP] Livechat Info * [IMPROVEMENT] Livechat info * [WIP] Livechat Edit * [WIP] Livechat edit * [WIP] Livechat Edit * [WIP] Livechat edit scroll * [FIX] Edit customFields * [FIX] Clean livechat customField * [FIX] Visitor Navigation * [NEW] Next input logic LivechatEdit * [FIX] Add livechat data to subscription * [FIX] Revert change * [NEW] Livechat user Status * [WIP] Livechat tags * [NEW] Edit livechat tags * [FIX] Prevent some crashes * [FIX] Forward * [FIX] Return Livechat error * [FIX] Prevent livechat info crash * [IMPROVEMENT] Use input style on forward chat * OnboardingSeparator -> OrSeparator * [FIX] Go to next input * [NEW] Added some icons * [NEW] Livechat close * [NEW] Forward Room Action * [FIX] Livechat edit style * [FIX] Change status logic * [CHORE] Remove unnecessary logic * [CHORE] Remove unnecessary code * [CHORE] Remove unecessary case * [FIX] Superfluous argument * [IMPROVEMENT] Submit livechat edit * [CHORE] Remove textInput type * [FIX] Livechat edit * [FIX] Livechat Edit * [FIX] Use same effect * [IMPROVEMENT] Tags input * [FIX] Add empty tag * Fix minor issues * Fix typo * insert livechat room data to our room object * review * add method calls server version Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-05-08 17:36:10 +00:00
onPress={onShow}
2020-02-11 14:01:35 +00:00
theme={theme}
loading={loading}
disabled={disabled}
inputStyle={inputStyle}
2020-02-11 14:01:35 +00:00
>
<Text style={[styles.pickerText, { color: currentValue ? themes[theme].titleText : themes[theme].auxiliaryText }]}>{currentValue || placeholder.text}</Text>
2020-02-11 14:01:35 +00:00
</Input>
);
if (context === BLOCK_CONTEXT.FORM) {
const items = options.filter(option => selected.includes(option.value));
2020-02-11 14:01:35 +00:00
button = (
<Input
[NEW] Livechat (#2004) * [WIP][NEW] Livechat info/actions * [IMPROVEMENT] RoomActionsView * [NEW] Visitor Navigation * [NEW] Get Department REST * [FIX] Borders * [IMPROVEMENT] Refactor RoomInfo View * [FIX] Error while navigate from mention -> roomInfo * [NEW] Livechat Fields * [NEW] Close Livechat * [WIP] Forward livechat * [NEW] Return inquiry * [WIP] Comment when close livechat * [WIP] Improve roomInfo * [IMPROVEMENT] Forward room * [FIX] Department picker * [FIX] Picker without results * [FIX] Superfluous argument * [FIX] Check permissions on RoomActionsView * [FIX] Livechat permissions * [WIP] Show edit to livechat * [I18N] Add pt-br translations * [WIP] Livechat Info * [IMPROVEMENT] Livechat info * [WIP] Livechat Edit * [WIP] Livechat edit * [WIP] Livechat Edit * [WIP] Livechat edit scroll * [FIX] Edit customFields * [FIX] Clean livechat customField * [FIX] Visitor Navigation * [NEW] Next input logic LivechatEdit * [FIX] Add livechat data to subscription * [FIX] Revert change * [NEW] Livechat user Status * [WIP] Livechat tags * [NEW] Edit livechat tags * [FIX] Prevent some crashes * [FIX] Forward * [FIX] Return Livechat error * [FIX] Prevent livechat info crash * [IMPROVEMENT] Use input style on forward chat * OnboardingSeparator -> OrSeparator * [FIX] Go to next input * [NEW] Added some icons * [NEW] Livechat close * [NEW] Forward Room Action * [FIX] Livechat edit style * [FIX] Change status logic * [CHORE] Remove unnecessary logic * [CHORE] Remove unnecessary code * [CHORE] Remove unecessary case * [FIX] Superfluous argument * [IMPROVEMENT] Submit livechat edit * [CHORE] Remove textInput type * [FIX] Livechat edit * [FIX] Livechat Edit * [FIX] Use same effect * [IMPROVEMENT] Tags input * [FIX] Add empty tag * Fix minor issues * Fix typo * insert livechat room data to our room object * review * add method calls server version Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-05-08 17:36:10 +00:00
onPress={onShow}
2020-02-11 14:01:35 +00:00
theme={theme}
loading={loading}
disabled={disabled}
inputStyle={inputStyle}
2020-02-11 14:01:35 +00:00
>
{items.length ? <Chips items={items} onSelect={item => (disabled ? {} : onSelect(item))} theme={theme} /> : <Text style={[styles.pickerText, { color: themes[theme].auxiliaryText }]}>{placeholder.text}</Text>}
2020-02-11 14:01:35 +00:00
</Input>
);
}
return (
<>
<Modal
animationType='fade'
transparent
visible={open}
onRequestClose={onHide}
onShow={onShow}
>
<TouchableWithoutFeedback onPress={onHide}>
<View style={styles.container}>
<View style={{ ...StyleSheet.absoluteFill, opacity: themes[theme].backdropOpacity, backgroundColor: themes[theme].backdropColor }} />
<KeyboardAvoidingView style={styles.keyboardView} behavior={behavior}>
2020-02-11 14:01:35 +00:00
<Animated.View style={[styles.animatedContent, { transform: [{ translateY }] }]}>
{showContent ? renderContent() : null}
</Animated.View>
</KeyboardAvoidingView>
</View>
</TouchableWithoutFeedback>
</Modal>
{button}
</>
);
});
MultiSelect.propTypes = {
options: PropTypes.array,
onChange: PropTypes.func,
placeholder: PropTypes.object,
context: PropTypes.number,
loading: PropTypes.bool,
multiselect: PropTypes.bool,
onSearch: PropTypes.func,
onClose: PropTypes.func,
inputStyle: PropTypes.object,
2020-02-11 14:01:35 +00:00
value: PropTypes.array,
disabled: PropTypes.bool,
2020-02-11 14:01:35 +00:00
theme: PropTypes.string
};
MultiSelect.defaultProps = {
onClose: () => {}
};