123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- import React, { useCallback } from 'react';
- import { useTranslation } from 'react-i18next';
- import { Platform, SafeAreaView, ScrollView, Text, View, ViewStyle } from 'react-native';
- import { useSelector } from 'react-redux';
-
- import { IReduxState } from '../../../app/types';
- import { IconSearch } from '../../../base/icons/svg';
- import JitsiScreen from '../../../base/modal/components/JitsiScreen';
- import LoadingIndicator from '../../../base/react/components/native/LoadingIndicator';
- import Button from '../../../base/ui/components/native/Button';
- import Input from '../../../base/ui/components/native/Input';
- import { BUTTON_TYPES } from '../../../base/ui/constants.native';
- import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
- import { screen } from '../../../mobile/navigation/routes';
- import { CONTENT_HEIGHT_OFFSET, LIST_HEIGHT_OFFSET, NOTES_LINES, NOTES_MAX_LENGTH } from '../../constants';
- import { useSalesforceLinkDialog } from '../../useSalesforceLinkDialog';
-
- import { RecordItem } from './RecordItem';
- import styles from './styles';
-
- /**
- * Component that renders the Salesforce link dialog.
- *
- * @returns {React$Element<any>}
- */
- const SalesforceLinkDialog = () => {
- const { t } = useTranslation();
- const { clientHeight } = useSelector((state: IReduxState) => state['features/base/responsive-ui']);
- const {
- hasDetailsErrors,
- hasRecordsErrors,
- isLoading,
- linkMeeting,
- notes,
- records,
- searchTerm,
- selectedRecord,
- selectedRecordOwner,
- setNotes,
- setSearchTerm,
- setSelectedRecord,
- showNoResults,
- showSearchResults
- } = useSalesforceLinkDialog();
-
- const handlePress = useCallback(() => {
- navigate(screen.conference.main);
- selectedRecord && linkMeeting();
- }, [ navigate, linkMeeting ]);
-
- const renderSpinner = () => (
- <View style = { [ styles.recordsSpinner, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
- <LoadingIndicator />
- </View>
- );
-
- const renderDetailsErrors = () => (
- <Text style = { styles.detailsError }>
- {t('dialog.searchResultsDetailsError')}
- </Text>
- );
-
- const renderSelection = () => (
- <SafeAreaView>
- <ScrollView
- bounces = { false }
- style = { [ styles.selectedRecord, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
- <View style = { styles.recordInfo as ViewStyle }>
- <RecordItem { ...selectedRecord } />
- { selectedRecordOwner && <RecordItem { ...selectedRecordOwner } /> }
- { hasDetailsErrors && renderDetailsErrors() }
- </View>
- <Text style = { styles.addNote }>
- {t('dialog.addOptionalNote')}
- </Text>
- <Input
- customStyles = {{ container: styles.notes }}
- maxLength = { NOTES_MAX_LENGTH }
- minHeight = { Platform.OS === 'ios' && NOTES_LINES ? 20 * NOTES_LINES : undefined }
- multiline = { true }
- numberOfLines = { Platform.OS === 'ios' ? undefined : NOTES_LINES }
- /* eslint-disable-next-line react/jsx-no-bind */
- onChange = { value => setNotes(value) }
- placeholder = { t('dialog.addMeetingNote') }
- value = { notes } />
- </ScrollView>
- </SafeAreaView>
- );
-
- const renderRecordsSearch = () => (
- <View style = { styles.recordsSearchContainer as ViewStyle }>
- <Input
- icon = { IconSearch }
- maxLength = { NOTES_MAX_LENGTH }
- /* eslint-disable-next-line react/jsx-no-bind */
- onChange = { value => setSearchTerm(value) }
- placeholder = { t('dialog.searchInSalesforce') }
- value = { searchTerm ?? '' } />
- {(!isLoading && !hasRecordsErrors) && (
- <Text style = { styles.resultLabel }>
- {showSearchResults
- ? t('dialog.searchResults', { count: records.length })
- : t('dialog.recentlyUsedObjects')
- }
- </Text>
- )}
- </View>
- );
-
- const renderNoRecords = () => showNoResults && (
- <View style = { [ styles.noRecords, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
- <Text style = { styles.noRecordsText }>
- {t('dialog.searchResultsNotFound')}
- </Text>
- <Text style = { styles.noRecordsText }>
- {t('dialog.searchResultsTryAgain')}
- </Text>
- </View>
- );
-
- const renderRecordsError = () => (
- <View style = { [ styles.recordsError, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
- <Text style = { styles.recordsErrorText }>
- {t('dialog.searchResultsError')}
- </Text>
- </View>
- );
-
- const renderContent = () => {
- if (isLoading) {
- return renderSpinner();
- }
- if (hasRecordsErrors) {
- return renderRecordsError();
- }
- if (showNoResults) {
- return renderNoRecords();
- }
- if (selectedRecord) {
- return renderSelection();
- }
-
- return (
- <SafeAreaView>
- <ScrollView
- bounces = { false }
- style = { [ styles.recordList, { height: clientHeight - LIST_HEIGHT_OFFSET } ] as ViewStyle[] }>
- {records.map((item: any) => (
- <RecordItem
- key = { `record-${item.id}` }
- /* eslint-disable-next-line react/jsx-no-bind */
- onClick = { () => setSelectedRecord(item) }
- { ...item } />
- ))}
- </ScrollView>
- </SafeAreaView>
- );
- };
-
- return (
- <JitsiScreen style = { styles.salesforceDialogContainer }>
- <View>
- {!selectedRecord && renderRecordsSearch()}
- {renderContent()}
- </View>
- {
- selectedRecord
- && <View>
- <Button
- labelKey = 'dialog.Cancel'
- /* eslint-disable-next-line react/jsx-no-bind */
- onClick = { () => setSelectedRecord(null) }
- style = { styles.cancelButton }
- type = { BUTTON_TYPES.SECONDARY } />
- <Button
- labelKey = 'dialog.linkMeeting'
- onClick = { handlePress }
- style = { styles.linkButton }
- type = { BUTTON_TYPES.PRIMARY } />
- </View>
- }
- </JitsiScreen>
- );
- };
-
- export default SalesforceLinkDialog;
|