Chore: Migrate CannedResponsesListView to Typescript (#3553)
* Chore: Migrate CannedResponsesListView to TS * Moved IcannedResponse to definitions and fixed the index * Chore: Migrate CannedResponseDetail to TS * minor tweaks * refactor: update new types and interfaces for use ISubscription * fix lint error and canned responses's dropdown Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
b95cad71eb
commit
6933278fd5
|
@ -22,7 +22,7 @@ const styles = StyleSheet.create({
|
||||||
|
|
||||||
interface ISearchHeaderProps {
|
interface ISearchHeaderProps {
|
||||||
onSearchChangeText?: (text: string) => void;
|
onSearchChangeText?: (text: string) => void;
|
||||||
testID: string;
|
testID?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchHeader = ({ onSearchChangeText, testID }: ISearchHeaderProps): JSX.Element => {
|
const SearchHeader = ({ onSearchChangeText, testID }: ISearchHeaderProps): JSX.Element => {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
export interface IDepartment {
|
||||||
|
_id: string;
|
||||||
|
enabled: boolean;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
showOnRegistration: boolean;
|
||||||
|
showOnOfflineForm: boolean;
|
||||||
|
requestTagBeforeClosingChat: boolean;
|
||||||
|
email: string;
|
||||||
|
chatClosingTags: string[];
|
||||||
|
offlineMessageChannelName: string;
|
||||||
|
maxNumberSimultaneousChat: number;
|
||||||
|
abandonedRoomsCloseCustomMessage: string;
|
||||||
|
waitingQueueMessage: string;
|
||||||
|
departmentsAllowedToForward: string;
|
||||||
|
_updatedAt: Date;
|
||||||
|
numAgents: number;
|
||||||
|
ancestors: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICannedResponse {
|
||||||
|
_id: string;
|
||||||
|
shortcut: string;
|
||||||
|
text: string;
|
||||||
|
scope: string;
|
||||||
|
tags: string[];
|
||||||
|
createdBy: { _id: string; username: string };
|
||||||
|
userId: string;
|
||||||
|
scopeName: string;
|
||||||
|
departmentId?: string;
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import { IServer } from '../definitions/IServer';
|
||||||
import { IAttachment } from '../definitions/IAttachment';
|
import { IAttachment } from '../definitions/IAttachment';
|
||||||
import { IMessage } from '../definitions/IMessage';
|
import { IMessage } from '../definitions/IMessage';
|
||||||
import { ISubscription, SubscriptionType, TSubscriptionModel } from '../definitions/ISubscription';
|
import { ISubscription, SubscriptionType, TSubscriptionModel } from '../definitions/ISubscription';
|
||||||
|
import { ICannedResponse } from '../definitions/ICannedResponse';
|
||||||
|
|
||||||
export type ChatsStackParamList = {
|
export type ChatsStackParamList = {
|
||||||
RoomsListView: undefined;
|
RoomsListView: undefined;
|
||||||
|
@ -137,12 +138,7 @@ export type ChatsStackParamList = {
|
||||||
rid: string;
|
rid: string;
|
||||||
};
|
};
|
||||||
CannedResponseDetail: {
|
CannedResponseDetail: {
|
||||||
cannedResponse: {
|
cannedResponse: ICannedResponse;
|
||||||
shortcut: string;
|
|
||||||
text: string;
|
|
||||||
scopeName: string;
|
|
||||||
tags: string[];
|
|
||||||
};
|
|
||||||
room: ISubscription;
|
room: ISubscription;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,6 +44,7 @@ export const goRoom = async ({
|
||||||
isMasterDetail: boolean;
|
isMasterDetail: boolean;
|
||||||
navigationMethod?: any;
|
navigationMethod?: any;
|
||||||
jumpToMessageId?: string;
|
jumpToMessageId?: string;
|
||||||
|
usedCannedResponse?: string;
|
||||||
}): Promise<void> => {
|
}): Promise<void> => {
|
||||||
if (item.t === SubscriptionType.DIRECT && item?.search) {
|
if (item.t === SubscriptionType.DIRECT && item?.search) {
|
||||||
// if user is using the search we need first to join/create room
|
// if user is using the search we need first to join/create room
|
||||||
|
@ -54,7 +55,7 @@ export const goRoom = async ({
|
||||||
return navigate({
|
return navigate({
|
||||||
item: {
|
item: {
|
||||||
rid: result.room._id,
|
rid: result.room._id,
|
||||||
name: username,
|
name: username || '',
|
||||||
t: SubscriptionType.DIRECT
|
t: SubscriptionType.DIRECT
|
||||||
},
|
},
|
||||||
isMasterDetail,
|
isMasterDetail,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
import { RouteProp } from '@react-navigation/native';
|
||||||
import { StyleSheet, Text, View, ScrollView } from 'react-native';
|
import { StyleSheet, Text, View, ScrollView } from 'react-native';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
@ -13,6 +14,8 @@ import Navigation from '../lib/Navigation';
|
||||||
import { goRoom } from '../utils/goRoom';
|
import { goRoom } from '../utils/goRoom';
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import Markdown from '../containers/markdown';
|
import Markdown from '../containers/markdown';
|
||||||
|
import { ICannedResponse } from '../definitions/ICannedResponse';
|
||||||
|
import { ChatsStackParamList } from '../stacks/types';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -68,27 +71,34 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Item = ({ label, content, theme, testID }) =>
|
interface IItem {
|
||||||
|
label: string;
|
||||||
|
content?: string;
|
||||||
|
theme: string;
|
||||||
|
testID?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Item = ({ label, content, theme, testID }: IItem) =>
|
||||||
content ? (
|
content ? (
|
||||||
<View style={styles.item} testID={testID}>
|
<View style={styles.item} testID={testID}>
|
||||||
<Text accessibilityLabel={label} style={[styles.itemLabel, { color: themes[theme].titleText }]}>
|
<Text accessibilityLabel={label} style={[styles.itemLabel, { color: themes[theme].titleText }]}>
|
||||||
{label}
|
{label}
|
||||||
</Text>
|
</Text>
|
||||||
|
{/* @ts-ignore */}
|
||||||
<Markdown style={[styles.itemContent, { color: themes[theme].auxiliaryText }]} msg={content} theme={theme} />
|
<Markdown style={[styles.itemContent, { color: themes[theme].auxiliaryText }]} msg={content} theme={theme} />
|
||||||
</View>
|
</View>
|
||||||
) : null;
|
) : null;
|
||||||
Item.propTypes = {
|
|
||||||
label: PropTypes.string,
|
|
||||||
content: PropTypes.string,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
testID: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
const CannedResponseDetail = ({ navigation, route }) => {
|
interface ICannedResponseDetailProps {
|
||||||
|
navigation: StackNavigationProp<ChatsStackParamList, 'CannedResponseDetail'>;
|
||||||
|
route: RouteProp<ChatsStackParamList, 'CannedResponseDetail'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CannedResponseDetail = ({ navigation, route }: ICannedResponseDetailProps): JSX.Element => {
|
||||||
const { cannedResponse } = route?.params;
|
const { cannedResponse } = route?.params;
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const { isMasterDetail } = useSelector(state => state.app);
|
const { isMasterDetail } = useSelector((state: any) => state.app);
|
||||||
const { rooms } = useSelector(state => state.room);
|
const { rooms } = useSelector((state: any) => state.room);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
|
@ -96,15 +106,14 @@ const CannedResponseDetail = ({ navigation, route }) => {
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const navigateToRoom = item => {
|
const navigateToRoom = (item: ICannedResponse) => {
|
||||||
const { room } = route.params;
|
const { room } = route.params;
|
||||||
const { name, username } = room;
|
const { name } = room;
|
||||||
const params = {
|
const params = {
|
||||||
rid: room.rid,
|
rid: room.rid,
|
||||||
name: RocketChat.getRoomTitle({
|
name: RocketChat.getRoomTitle({
|
||||||
t: room.t,
|
t: room.t,
|
||||||
fname: name,
|
fname: name
|
||||||
name: username
|
|
||||||
}),
|
}),
|
||||||
t: room.t,
|
t: room.t,
|
||||||
roomUserId: RocketChat.getUidDirectMessage(room),
|
roomUserId: RocketChat.getUidDirectMessage(room),
|
||||||
|
@ -115,7 +124,7 @@ const CannedResponseDetail = ({ navigation, route }) => {
|
||||||
// if it's on master detail layout, we close the modal and replace RoomView
|
// if it's on master detail layout, we close the modal and replace RoomView
|
||||||
if (isMasterDetail) {
|
if (isMasterDetail) {
|
||||||
Navigation.navigate('DrawerNavigator');
|
Navigation.navigate('DrawerNavigator');
|
||||||
goRoom({ item: params, isMasterDetail, usedCannedResponse: item.text });
|
goRoom({ item: params, isMasterDetail });
|
||||||
} else {
|
} else {
|
||||||
let navigate = navigation.push;
|
let navigate = navigation.push;
|
||||||
// if this is a room focused
|
// if this is a room focused
|
||||||
|
@ -163,9 +172,4 @@ const CannedResponseDetail = ({ navigation, route }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
CannedResponseDetail.propTypes = {
|
|
||||||
navigation: PropTypes.object,
|
|
||||||
route: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CannedResponseDetail;
|
export default CannedResponseDetail;
|
|
@ -1,14 +1,31 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { View, Text } from 'react-native';
|
import { View, Text } from 'react-native';
|
||||||
|
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import Button from '../../containers/Button';
|
import Button from '../../containers/Button';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
const CannedResponseItem = ({ theme, onPressDetail, shortcut, scope, onPressUse, text, tags }) => (
|
interface ICannedResponseItem {
|
||||||
|
theme: string;
|
||||||
|
onPressDetail: () => void;
|
||||||
|
shortcut: string;
|
||||||
|
scope: string;
|
||||||
|
onPressUse: () => void;
|
||||||
|
text: string;
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const CannedResponseItem = ({
|
||||||
|
theme,
|
||||||
|
onPressDetail = () => {},
|
||||||
|
shortcut,
|
||||||
|
scope,
|
||||||
|
onPressUse = () => {},
|
||||||
|
text,
|
||||||
|
tags
|
||||||
|
}: ICannedResponseItem): JSX.Element => (
|
||||||
<Touchable onPress={onPressDetail} style={[styles.wrapCannedItem, { backgroundColor: themes[theme].messageboxBackground }]}>
|
<Touchable onPress={onPressDetail} style={[styles.wrapCannedItem, { backgroundColor: themes[theme].messageboxBackground }]}>
|
||||||
<>
|
<>
|
||||||
<View style={styles.cannedRow}>
|
<View style={styles.cannedRow}>
|
||||||
|
@ -43,19 +60,4 @@ const CannedResponseItem = ({ theme, onPressDetail, shortcut, scope, onPressUse,
|
||||||
</Touchable>
|
</Touchable>
|
||||||
);
|
);
|
||||||
|
|
||||||
CannedResponseItem.propTypes = {
|
|
||||||
theme: PropTypes.string,
|
|
||||||
onPressDetail: PropTypes.func,
|
|
||||||
shortcut: PropTypes.string,
|
|
||||||
scope: PropTypes.string,
|
|
||||||
onPressUse: PropTypes.func,
|
|
||||||
text: PropTypes.string,
|
|
||||||
tags: PropTypes.array
|
|
||||||
};
|
|
||||||
|
|
||||||
CannedResponseItem.defaultProps = {
|
|
||||||
onPressDetail: () => {},
|
|
||||||
onPressUse: () => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CannedResponseItem;
|
export default CannedResponseItem;
|
|
@ -1,44 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
|
||||||
|
|
||||||
import { themes } from '../../../constants/colors';
|
|
||||||
import { withTheme } from '../../../theme';
|
|
||||||
import Touch from '../../../utils/touch';
|
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
|
||||||
import sharedStyles from '../../Styles';
|
|
||||||
|
|
||||||
export const ROW_HEIGHT = 44;
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
paddingVertical: 11,
|
|
||||||
height: ROW_HEIGHT,
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center'
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
flex: 1,
|
|
||||||
fontSize: 16,
|
|
||||||
...sharedStyles.textRegular
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const DropdownItem = React.memo(({ theme, onPress, iconName, text }) => (
|
|
||||||
<Touch theme={theme} onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }}>
|
|
||||||
<View style={styles.container}>
|
|
||||||
<Text style={[styles.text, { color: themes[theme].auxiliaryText }]}>{text}</Text>
|
|
||||||
{iconName ? <CustomIcon name={iconName} size={22} color={themes[theme].auxiliaryText} /> : null}
|
|
||||||
</View>
|
|
||||||
</Touch>
|
|
||||||
));
|
|
||||||
|
|
||||||
DropdownItem.propTypes = {
|
|
||||||
text: PropTypes.string,
|
|
||||||
iconName: PropTypes.string,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
onPress: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withTheme(DropdownItem);
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import { themes } from '../../../constants/colors';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
import Touch from '../../../utils/touch';
|
||||||
|
import { CustomIcon } from '../../../lib/Icons';
|
||||||
|
import sharedStyles from '../../Styles';
|
||||||
|
|
||||||
|
export const ROW_HEIGHT = 44;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
paddingVertical: 11,
|
||||||
|
height: ROW_HEIGHT,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
flex: 1,
|
||||||
|
fontSize: 16,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface IDropdownItem {
|
||||||
|
text: string;
|
||||||
|
iconName: string | null;
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DropdownItem = React.memo(({ onPress, iconName, text }: IDropdownItem) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Touch theme={theme} onPress={onPress} style={{ backgroundColor: themes[theme].backgroundColor }}>
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={[styles.text, { color: themes[theme].auxiliaryText }]}>{text}</Text>
|
||||||
|
{iconName ? <CustomIcon name={iconName} size={22} color={themes[theme].auxiliaryText} /> : null}
|
||||||
|
</View>
|
||||||
|
</Touch>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default DropdownItem;
|
|
@ -1,9 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
|
import { IDepartment } from '../../../definitions/ICannedResponse';
|
||||||
import DropdownItem from './DropdownItem';
|
import DropdownItem from './DropdownItem';
|
||||||
|
|
||||||
const DropdownItemFilter = ({ currentDepartment, value, onPress }) => (
|
interface IDropdownItemFilter {
|
||||||
|
currentDepartment: IDepartment;
|
||||||
|
value: IDepartment;
|
||||||
|
onPress: (value: IDepartment) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DropdownItemFilter = ({ currentDepartment, value, onPress }: IDropdownItemFilter): JSX.Element => (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
text={value?.name}
|
text={value?.name}
|
||||||
iconName={currentDepartment?._id === value?._id ? 'check' : null}
|
iconName={currentDepartment?._id === value?._id ? 'check' : null}
|
||||||
|
@ -11,10 +17,4 @@ const DropdownItemFilter = ({ currentDepartment, value, onPress }) => (
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
DropdownItemFilter.propTypes = {
|
|
||||||
currentDepartment: PropTypes.object,
|
|
||||||
value: PropTypes.string,
|
|
||||||
onPress: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DropdownItemFilter;
|
export default DropdownItemFilter;
|
|
@ -1,15 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import DropdownItem from './DropdownItem';
|
|
||||||
|
|
||||||
const DropdownItemHeader = ({ department, onPress }) => (
|
|
||||||
<DropdownItem text={department?.name} iconName='filter' onPress={onPress} />
|
|
||||||
);
|
|
||||||
|
|
||||||
DropdownItemHeader.propTypes = {
|
|
||||||
department: PropTypes.object,
|
|
||||||
onPress: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DropdownItemHeader;
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { IDepartment } from '../../../definitions/ICannedResponse';
|
||||||
|
import DropdownItem from './DropdownItem';
|
||||||
|
|
||||||
|
interface IDropdownItemHeader {
|
||||||
|
department: IDepartment;
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DropdownItemHeader = ({ department, onPress }: IDropdownItemHeader): JSX.Element => (
|
||||||
|
<DropdownItem text={department?.name} iconName='filter' onPress={onPress} />
|
||||||
|
);
|
||||||
|
|
||||||
|
export default DropdownItemHeader;
|
|
@ -1,31 +1,30 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Animated, Easing, FlatList, TouchableWithoutFeedback } from 'react-native';
|
import { Animated, Easing, FlatList, TouchableWithoutFeedback } from 'react-native';
|
||||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import { withTheme } from '../../../theme';
|
import { withTheme } from '../../../theme';
|
||||||
import { headerHeight } from '../../../containers/Header';
|
|
||||||
import * as List from '../../../containers/List';
|
import * as List from '../../../containers/List';
|
||||||
|
import { IDepartment } from '../../../definitions/ICannedResponse';
|
||||||
import DropdownItemFilter from './DropdownItemFilter';
|
import DropdownItemFilter from './DropdownItemFilter';
|
||||||
import DropdownItemHeader from './DropdownItemHeader';
|
import DropdownItemHeader from './DropdownItemHeader';
|
||||||
import { ROW_HEIGHT } from './DropdownItem';
|
import { ROW_HEIGHT } from './DropdownItem';
|
||||||
|
|
||||||
const ANIMATION_DURATION = 200;
|
const ANIMATION_DURATION = 200;
|
||||||
|
|
||||||
class Dropdown extends React.Component {
|
interface IDropdownProps {
|
||||||
static propTypes = {
|
theme?: string;
|
||||||
isMasterDetail: PropTypes.bool,
|
currentDepartment: IDepartment;
|
||||||
theme: PropTypes.string,
|
onClose: () => void;
|
||||||
insets: PropTypes.object,
|
onDepartmentSelected: (value: IDepartment) => void;
|
||||||
currentDepartment: PropTypes.object,
|
departments: IDepartment[];
|
||||||
onClose: PropTypes.func,
|
}
|
||||||
onDepartmentSelected: PropTypes.func,
|
|
||||||
departments: PropTypes.array
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
class Dropdown extends React.Component<IDropdownProps> {
|
||||||
|
private animatedValue: Animated.Value;
|
||||||
|
|
||||||
|
constructor(props: IDropdownProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.animatedValue = new Animated.Value(0);
|
this.animatedValue = new Animated.Value(0);
|
||||||
}
|
}
|
||||||
|
@ -50,16 +49,15 @@ class Dropdown extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isMasterDetail, insets, theme, currentDepartment, onDepartmentSelected, departments } = this.props;
|
const { theme, currentDepartment, onDepartmentSelected, departments } = this.props;
|
||||||
const statusBarHeight = insets?.top ?? 0;
|
const heightDestination = 0;
|
||||||
const heightDestination = isMasterDetail ? headerHeight + statusBarHeight : 0;
|
|
||||||
const translateY = this.animatedValue.interpolate({
|
const translateY = this.animatedValue.interpolate({
|
||||||
inputRange: [0, 1],
|
inputRange: [0, 1],
|
||||||
outputRange: [-300, heightDestination] // approximated height of the component when closed/open
|
outputRange: [-300, heightDestination] // approximated height of the component when closed/open
|
||||||
});
|
});
|
||||||
const backdropOpacity = this.animatedValue.interpolate({
|
const backdropOpacity = this.animatedValue.interpolate({
|
||||||
inputRange: [0, 1],
|
inputRange: [0, 1],
|
||||||
outputRange: [0, themes[theme].backdropOpacity]
|
outputRange: [0, themes[theme!].backdropOpacity]
|
||||||
});
|
});
|
||||||
|
|
||||||
const maxRows = 5;
|
const maxRows = 5;
|
||||||
|
@ -70,7 +68,7 @@ class Dropdown extends React.Component {
|
||||||
style={[
|
style={[
|
||||||
styles.backdrop,
|
styles.backdrop,
|
||||||
{
|
{
|
||||||
backgroundColor: themes[theme].backdropColor,
|
backgroundColor: themes[theme!].backdropColor,
|
||||||
opacity: backdropOpacity,
|
opacity: backdropOpacity,
|
||||||
top: heightDestination
|
top: heightDestination
|
||||||
}
|
}
|
||||||
|
@ -82,8 +80,8 @@ class Dropdown extends React.Component {
|
||||||
styles.dropdownContainer,
|
styles.dropdownContainer,
|
||||||
{
|
{
|
||||||
transform: [{ translateY }],
|
transform: [{ translateY }],
|
||||||
backgroundColor: themes[theme].backgroundColor,
|
backgroundColor: themes[theme!].backgroundColor,
|
||||||
borderColor: themes[theme].separatorColor
|
borderColor: themes[theme!].separatorColor
|
||||||
}
|
}
|
||||||
]}>
|
]}>
|
||||||
<DropdownItemHeader department={currentDepartment} onPress={this.close} />
|
<DropdownItemHeader department={currentDepartment} onPress={this.close} />
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import React, { useEffect, useState, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { FlatList } from 'react-native';
|
import { FlatList } from 'react-native';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import { HeaderBackButton } from '@react-navigation/stack';
|
import { RouteProp } from '@react-navigation/native';
|
||||||
|
import { HeaderBackButton, StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
|
@ -26,6 +26,9 @@ import CannedResponseItem from './CannedResponseItem';
|
||||||
import Dropdown from './Dropdown';
|
import Dropdown from './Dropdown';
|
||||||
import DropdownItemHeader from './Dropdown/DropdownItemHeader';
|
import DropdownItemHeader from './Dropdown/DropdownItemHeader';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { ICannedResponse, IDepartment } from '../../definitions/ICannedResponse';
|
||||||
|
import { ChatsStackParamList } from '../../stacks/types';
|
||||||
|
import { ISubscription } from '../../definitions/ISubscription';
|
||||||
|
|
||||||
const COUNT = 25;
|
const COUNT = 25;
|
||||||
|
|
||||||
|
@ -42,14 +45,19 @@ const fixedScopes = [
|
||||||
_id: 'user',
|
_id: 'user',
|
||||||
name: I18n.t('Private')
|
name: I18n.t('Private')
|
||||||
}
|
}
|
||||||
];
|
] as IDepartment[];
|
||||||
|
|
||||||
const CannedResponsesListView = ({ navigation, route }) => {
|
interface ICannedResponsesListViewProps {
|
||||||
const [room, setRoom] = useState(null);
|
navigation: StackNavigationProp<ChatsStackParamList, 'CannedResponsesListView'>;
|
||||||
|
route: RouteProp<ChatsStackParamList, 'CannedResponsesListView'>;
|
||||||
|
}
|
||||||
|
|
||||||
const [cannedResponses, setCannedResponses] = useState([]);
|
const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListViewProps): JSX.Element => {
|
||||||
const [cannedResponsesScopeName, setCannedResponsesScopeName] = useState([]);
|
const [room, setRoom] = useState<ISubscription | null>(null);
|
||||||
const [departments, setDepartments] = useState([]);
|
|
||||||
|
const [cannedResponses, setCannedResponses] = useState<ICannedResponse[]>([]);
|
||||||
|
const [cannedResponsesScopeName, setCannedResponsesScopeName] = useState<ICannedResponse[]>([]);
|
||||||
|
const [departments, setDepartments] = useState<IDepartment[]>([]);
|
||||||
|
|
||||||
// states used by the filter in Header and Dropdown
|
// states used by the filter in Header and Dropdown
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
|
@ -65,8 +73,8 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
|
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const { isMasterDetail } = useSelector(state => state.app);
|
const { isMasterDetail } = useSelector((state: any) => state.app);
|
||||||
const { rooms } = useSelector(state => state.room);
|
const { rooms } = useSelector((state: any) => state.room);
|
||||||
|
|
||||||
const getRoomFromDb = async () => {
|
const getRoomFromDb = async () => {
|
||||||
const { rid } = route.params;
|
const { rid } = route.params;
|
||||||
|
@ -93,21 +101,22 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
const goToDetail = item => {
|
const goToDetail = (item: ICannedResponse) => {
|
||||||
|
if (room) {
|
||||||
navigation.navigate('CannedResponseDetail', { cannedResponse: item, room });
|
navigation.navigate('CannedResponseDetail', { cannedResponse: item, room });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateToRoom = item => {
|
const navigateToRoom = (item: ICannedResponse) => {
|
||||||
if (!room) {
|
if (!room) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { name, username } = room;
|
const { name } = room;
|
||||||
const params = {
|
const params = {
|
||||||
rid: room.rid,
|
rid: room.rid,
|
||||||
name: RocketChat.getRoomTitle({
|
name: RocketChat.getRoomTitle({
|
||||||
t: room.t,
|
t: room.t,
|
||||||
fname: name,
|
fname: name
|
||||||
name: username
|
|
||||||
}),
|
}),
|
||||||
t: room.t,
|
t: room.t,
|
||||||
roomUserId: RocketChat.getUidDirectMessage(room),
|
roomUserId: RocketChat.getUidDirectMessage(room),
|
||||||
|
@ -118,7 +127,7 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
// if it's on master detail layout, we close the modal and replace RoomView
|
// if it's on master detail layout, we close the modal and replace RoomView
|
||||||
if (isMasterDetail) {
|
if (isMasterDetail) {
|
||||||
Navigation.navigate('DrawerNavigator');
|
Navigation.navigate('DrawerNavigator');
|
||||||
goRoom({ item: params, isMasterDetail, usedCannedResponse: item.text });
|
goRoom({ item: params, isMasterDetail });
|
||||||
} else {
|
} else {
|
||||||
let navigate = navigation.push;
|
let navigate = navigation.push;
|
||||||
// if this is a room focused
|
// if this is a room focused
|
||||||
|
@ -130,7 +139,17 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getListCannedResponse = async ({ text, department, depId, debounced }) => {
|
const getListCannedResponse = async ({
|
||||||
|
text,
|
||||||
|
department,
|
||||||
|
depId,
|
||||||
|
debounced
|
||||||
|
}: {
|
||||||
|
text: string;
|
||||||
|
department: string;
|
||||||
|
depId: string;
|
||||||
|
debounced: boolean;
|
||||||
|
}) => {
|
||||||
try {
|
try {
|
||||||
const res = await RocketChat.getListCannedResponse({
|
const res = await RocketChat.getListCannedResponse({
|
||||||
text,
|
text,
|
||||||
|
@ -188,13 +207,13 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
setOffset(0);
|
setOffset(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChangeText = text => {
|
const onChangeText = (text: string) => {
|
||||||
newSearch();
|
newSearch();
|
||||||
setSearchText(text);
|
setSearchText(text);
|
||||||
searchCallback(text, scope, departmentId);
|
searchCallback(text, scope, departmentId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDepartmentSelect = value => {
|
const onDepartmentSelect = (value: IDepartment) => {
|
||||||
let department = '';
|
let department = '';
|
||||||
let depId = '';
|
let depId = '';
|
||||||
|
|
||||||
|
@ -225,7 +244,7 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
await getListCannedResponse({ text: searchText, department: scope, depId: departmentId, debounced: false });
|
await getListCannedResponse({ text: searchText, department: scope, depId: departmentId, debounced: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
const getHeader = () => {
|
const getHeader = (): StackNavigationOptions => {
|
||||||
if (isSearching) {
|
if (isSearching) {
|
||||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
||||||
return {
|
return {
|
||||||
|
@ -235,7 +254,7 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
<HeaderButton.Item
|
<HeaderButton.Item
|
||||||
iconName='close'
|
iconName='close'
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
onChangeText();
|
onChangeText('');
|
||||||
setIsSearching(false);
|
setIsSearching(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -250,7 +269,7 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const options: StackNavigationOptions = {
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />
|
<HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />
|
||||||
),
|
),
|
||||||
|
@ -355,9 +374,4 @@ const CannedResponsesListView = ({ navigation, route }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
CannedResponsesListView.propTypes = {
|
|
||||||
navigation: PropTypes.object,
|
|
||||||
route: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CannedResponsesListView;
|
export default CannedResponsesListView;
|
|
@ -13,7 +13,7 @@ export default StyleSheet.create({
|
||||||
borderBottomWidth: StyleSheet.hairlineWidth
|
borderBottomWidth: StyleSheet.hairlineWidth
|
||||||
},
|
},
|
||||||
backdrop: {
|
backdrop: {
|
||||||
...StyleSheet.absoluteFill
|
...StyleSheet.absoluteFillObject
|
||||||
},
|
},
|
||||||
wrapCannedItem: {
|
wrapCannedItem: {
|
||||||
minHeight: 117,
|
minHeight: 117,
|
Loading…
Reference in New Issue