diff --git a/app/lib/rocketchat/rocketchat.js b/app/lib/rocketchat/rocketchat.js index eea650e88..b2171eacd 100644 --- a/app/lib/rocketchat/rocketchat.js +++ b/app/lib/rocketchat/rocketchat.js @@ -821,7 +821,6 @@ const RocketChat = { return sdk.methodCallWrapper(method, ...params); }, getUserInfo, - getUidDirectMessage(room) { const { id: userId } = reduxStore.getState().login.user; diff --git a/app/lib/rocketchat/services/restApi.ts b/app/lib/rocketchat/services/restApi.ts index 2c9e833c4..3fc518123 100644 --- a/app/lib/rocketchat/services/restApi.ts +++ b/app/lib/rocketchat/services/restApi.ts @@ -421,9 +421,18 @@ export const getDepartmentInfo = (departmentId: string): any => // RC 2.2.0 sdk.get(`livechat/department/${departmentId}?includeAgents=false`); -export const getDepartments = () => +export const getDepartments = (args?: { count: number; offset: number; text: string }) => { + let params; + if (args) { + params = { + text: args.text, + count: args.count, + offset: args.offset + }; + } // RC 2.2.0 - sdk.get('livechat/department'); + return sdk.get('livechat/department', params); +}; export const usersAutoComplete = (selector: any) => // RC 2.4.0 diff --git a/app/stacks/types.ts b/app/stacks/types.ts index 002f5e6d7..7e5e571b5 100644 --- a/app/stacks/types.ts +++ b/app/stacks/types.ts @@ -102,8 +102,10 @@ export type ChatsStackParamList = { PickerView: { title: string; data: IOptionsField[]; - value?: any; // TODO: Change - onChangeText?: ((text: string) => IOptionsField[]) | ((term?: string) => Promise); + value?: string; + onSearch?: (text?: string) => Promise; + onEndReached?: (text: string, offset?: number) => Promise; + total?: number; goBack?: boolean; onChangeValue: Function; }; diff --git a/app/views/ForwardLivechatView.tsx b/app/views/ForwardLivechatView.tsx index 9e3cfe915..ff0840750 100644 --- a/app/views/ForwardLivechatView.tsx +++ b/app/views/ForwardLivechatView.tsx @@ -13,8 +13,9 @@ import RocketChat from '../lib/rocketchat'; import OrSeparator from '../containers/OrSeparator'; import Input from '../containers/UIKit/MultiSelect/Input'; import { forwardRoom as forwardRoomAction } from '../actions/room'; -import { ILivechatDepartment } from './definition/ILivechatDepartment'; +import { IRoom } from '../definitions'; import { ChatsStackParamList } from '../stacks/types'; +import { IOptionsField } from './NotificationPreferencesView/options'; const styles = StyleSheet.create({ container: { @@ -23,14 +24,6 @@ const styles = StyleSheet.create({ } }); -// TODO: Refactor when migrate room -interface IRoom { - departmentId?: any; - servedBy?: { - _id: string; - }; -} - interface ITransferData { roomId: string; userId?: string; @@ -41,12 +34,6 @@ interface IUser { username: string; _id: string; } - -interface IParsedData { - label: string; - value: string; -} - interface IForwardLivechatViewProps { navigation: StackNavigationProp; route: RouteProp; @@ -54,22 +41,31 @@ interface IForwardLivechatViewProps { forwardRoom: (rid: string, transferData: ITransferData) => void; } +const COUNT_DEPARTMENT = 50; + const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForwardLivechatViewProps) => { - const [departments, setDepartments] = useState([]); + const [departments, setDepartments] = useState([]); const [departmentId, setDepartment] = useState(''); - const [users, setUsers] = useState([]); + const [departmentTotal, setDepartmentTotal] = useState(0); + const [users, setUsers] = useState([]); const [userId, setUser] = useState(); - const [room, setRoom] = useState({}); + const [room, setRoom] = useState({} as IRoom); const rid = route.params?.rid; - const getDepartments = async () => { + const getDepartments = async (text = '', offset = 0) => { try { - const result: any = await RocketChat.getDepartments(); + const result = await RocketChat.getDepartments({ count: COUNT_DEPARTMENT, text, offset }); if (result.success) { - setDepartments( - result.departments.map((department: ILivechatDepartment) => ({ label: department.name, value: department._id })) - ); + const parsedDepartments: IOptionsField[] = result.departments.map(department => ({ + label: department.name, + value: department._id + })); + if (!text && !offset) { + setDepartments(parsedDepartments); + setDepartmentTotal(result?.total); + } + return { data: parsedDepartments, total: result?.total, offset: result?.offset }; } } catch { // do nothing @@ -80,26 +76,27 @@ const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForward try { const { servedBy: { _id: agentId } = {} } = room; const _id = agentId && { $ne: agentId }; - const result: any = await RocketChat.usersAutoComplete({ + const result = await RocketChat.usersAutoComplete({ conditions: { _id, status: { $ne: 'offline' }, statusLivechat: 'available' }, term }); if (result.success) { const parsedUsers = result.items.map((user: IUser) => ({ label: user.username, value: user._id })); - setUsers(parsedUsers); - return parsedUsers; + if (!term) { + setUsers(parsedUsers); + } + return { data: parsedUsers }; } } catch { // do nothing } - return []; }; const getRoom = async () => { try { const result = await RocketChat.getRoomInfo(rid); if (result.success) { - setRoom(result.room); + setRoom(result.room as IRoom); } } catch { // do nothing @@ -148,6 +145,9 @@ const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForward value: room?.departmentId, data: departments, onChangeValue: setDepartment, + onSearch: getDepartments, + onEndReached: getDepartments, + total: departmentTotal, goBack: false }); }; @@ -157,7 +157,7 @@ const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForward title: I18n.t('Forward_to_user'), data: users, onChangeValue: setUser, - onChangeText: getUsers, + onSearch: getUsers, goBack: false }); }; diff --git a/app/views/PickerView.tsx b/app/views/PickerView.tsx index cf2f99d6d..c00d00c83 100644 --- a/app/views/PickerView.tsx +++ b/app/views/PickerView.tsx @@ -24,6 +24,9 @@ const styles = StyleSheet.create({ paddingVertical: 56, ...sharedStyles.textSemibold, ...sharedStyles.textAlignCenter + }, + listNoHeader: { + marginTop: 32 } }); @@ -34,9 +37,16 @@ interface IItem { theme: string; } +interface IRenderSearch { + hasSearch: boolean; + onChangeText: (text: string) => void; +} + interface IPickerViewState { data: IOptionsField[]; value: string; + total: number; + searchText: string; } interface IPickerViewProps { @@ -54,8 +64,22 @@ const Item = React.memo(({ item, selected, onItemPress, theme }: IItem) => ( /> )); +const RenderSearch = ({ hasSearch, onChangeText }: IRenderSearch) => { + if (!hasSearch) { + return ; + } + return ( + <> + + + + + + ); +}; + class PickerView extends React.PureComponent { - private onSearch?: ((text: string) => IOptionsField[]) | ((term?: string | undefined) => Promise); + private onSearch?: (text?: string) => Promise; static navigationOptions = ({ route }: IPickerViewProps) => ({ title: route.params?.title ?? I18n.t('Select_an_option') @@ -64,10 +88,10 @@ class PickerView extends React.PureComponent constructor(props: IPickerViewProps) { super(props); const data = props.route.params?.data ?? []; - const value = props.route.params?.value; - this.state = { data, value }; - - this.onSearch = props.route.params?.onChangeText; + const value = props.route.params?.value ?? ''; + const total = props.route.params?.total ?? 0; + this.state = { data, value, total, searchText: '' }; + this.onSearch = props.route.params?.onSearch; } onChangeValue = (value: string) => { @@ -80,28 +104,26 @@ class PickerView extends React.PureComponent } }; - onChangeText = debounce( - async (text: string) => { - if (this.onSearch) { - const data = await this.onSearch(text); - this.setState({ data }); + onChangeText = debounce(async (searchText: string) => { + if (this.onSearch) { + const data = await this.onSearch(searchText); + if (data?.data) { + this.setState({ ...data, searchText }); } - }, - 300, - true - ); - - renderSearch() { - if (!this.onSearch) { - return null; } + }, 500); - return ( - - - - ); - } + onEndReached = async () => { + const { route } = this.props; + const { data, total, searchText } = this.state; + const onEndReached = route.params?.onEndReached; + if (onEndReached && data.length < total) { + const val = await onEndReached(searchText, data.length); + if (val?.data) { + this.setState({ ...val, data: [...data, ...val.data] }); + } + } + }; render() { const { data, value } = this.state; @@ -109,7 +131,6 @@ class PickerView extends React.PureComponent return ( - {this.renderSearch()} item.value as string} @@ -121,13 +142,14 @@ class PickerView extends React.PureComponent onItemPress={() => this.onChangeValue(item.value as string)} /> )} + onEndReached={() => this.onEndReached()} + onEndReachedThreshold={0.5} ItemSeparatorComponent={List.Separator} - ListHeaderComponent={List.Separator} + ListHeaderComponent={} ListFooterComponent={List.Separator} ListEmptyComponent={() => ( {I18n.t('No_results_found')} )} - contentContainerStyle={[List.styles.contentContainerStyleFlatList]} /> );