import debounce from '@ringcentral-integration/commons/lib/debounce';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { includes } from 'ramda';
import React, { Component } from 'react';
import AddContactIcon from '../../assets/images/ContactAdd.svg';
import RefreshingIcon from '../../assets/images/OvalLoading.svg';
import RefreshContactIcon from '../../assets/images/RetryIcon.svg';
import ContactList from '../ContactList';
import { ContactSourceFilter } from '../ContactSourceFilter';
import Panel from '../Panel';
import { SearchInput } from '../SearchInput';
import { SpinnerOverlay } from '../SpinnerOverlay';
import i18n from './i18n';
import styles from './styles.scss';
// @ts-expect-error
const AddContact = ({ className, onClick }) => {
return (
);
};
AddContact.propTypes = {
className: PropTypes.string,
onClick: PropTypes.func.isRequired,
};
AddContact.defaultProps = {
className: undefined,
};
const RefreshContacts = ({
// @ts-expect-error
className,
// @ts-expect-error
onRefresh,
// @ts-expect-error
refreshing,
// @ts-expect-error
currentLocale,
}) => {
let icon = null;
let iconWrapClass = null;
if (refreshing) {
iconWrapClass = styles.refreshingIcon;
icon = (
);
} else {
iconWrapClass = styles.refreshIcon;
icon = (
);
}
return (
);
};
RefreshContacts.propTypes = {
className: PropTypes.string,
currentLocale: PropTypes.string.isRequired,
onRefresh: PropTypes.func.isRequired,
refreshing: PropTypes.bool.isRequired,
};
RefreshContacts.defaultProps = {
className: undefined,
};
class ContactsView extends Component {
// @ts-expect-error
constructor(props) {
super(props);
this.state = {
searchString: props.searchString,
lastInputTimestamp: 0,
unfold: false,
contentHeight: 0,
contentWidth: 0,
refreshing: false,
};
// @ts-expect-error
this.contactList = React.createRef();
// @ts-expect-error
this.contentWrapper = React.createRef();
// @ts-expect-error
this.onUnfoldChange = (unfold) => {
this.setState({
unfold,
});
};
}
calculateContentSize = () => {
if (
// @ts-expect-error
this.contentWrapper &&
// @ts-expect-error
this.contentWrapper.current &&
// @ts-expect-error
this.contentWrapper.current.getBoundingClientRect
) {
// @ts-expect-error
const rect = this.contentWrapper.current.getBoundingClientRect();
return {
contentHeight: rect.bottom - rect.top,
contentWidth: rect.right - rect.left,
};
}
return {
contentHeight: 0,
contentWidth: 0,
};
};
// @ts-expect-error
componentDidMount() {
// @ts-expect-error
this._mounted = true;
// @ts-expect-error
const { onVisitPage } = this.props;
if (typeof onVisitPage === 'function') {
onVisitPage();
}
this.setState({
...this.calculateContentSize(),
});
window.addEventListener('resize', this.onResize);
}
// @ts-expect-error
UNSAFE_componentWillUpdate(nextProps, nextState) {
// @ts-expect-error
const { lastInputTimestamp } = this.state;
// @ts-expect-error
const { searchString: searchStringProp } = this.props;
// sync search string from other app instance
const isNotEditing = Date.now() - lastInputTimestamp > 2000;
if (isNotEditing && nextProps.searchString !== searchStringProp) {
nextState.searchString = nextProps.searchString;
}
// default to the first contact source when current selected contact source is removed
if (!includes(nextProps.searchSource, nextProps.contactSourceNames)) {
// @ts-expect-error
const { searchString } = this.state;
this.search({
searchSource: nextProps.contactSourceNames[0],
searchString,
});
}
}
// @ts-expect-error
componentWillUnmount() {
// @ts-expect-error
this._mounted = false;
window.removeEventListener('resize', this.onResize);
}
// @ts-expect-error
onSearchInputChange = (ev) => {
this.setState(
{
searchString: ev.target.value,
lastInputTimestamp: Date.now(),
},
() => {
// @ts-expect-error
const { searchString } = this.state;
// @ts-expect-error
const { searchSource } = this.props;
this.search({
searchString,
searchSource,
});
},
);
};
// @ts-expect-error
onSourceSelect = (searchSource) => {
if (
// @ts-expect-error
this.contactList &&
// @ts-expect-error
this.contactList.current &&
// @ts-expect-error
this.contactList.current.resetScrollTop
) {
// @ts-expect-error
this.contactList.current.resetScrollTop();
}
// @ts-expect-error
const { searchString } = this.state;
this.search({
searchSource,
searchString,
});
};
onResize = debounce(() => {
// @ts-expect-error
if (this._mounted) {
this.setState({
...this.calculateContentSize(),
});
}
}, 300);
onRefresh = async () => {
// @ts-expect-error
const { onRefresh } = this.props;
if (typeof onRefresh === 'function') {
this.setState({ refreshing: true }, async () => {
await onRefresh();
this.setState({ refreshing: false });
});
}
};
// @ts-expect-error
search({ searchSource, searchString }) {
// @ts-expect-error
const { onSearchContact } = this.props;
if (typeof onSearchContact === 'function') {
onSearchContact({
searchSource,
searchString,
});
}
}
// @ts-expect-error
render() {
const {
// @ts-expect-error
currentLocale,
// @ts-expect-error
contactGroups,
// @ts-expect-error
contactSourceNames,
// @ts-expect-error
searchSource,
// @ts-expect-error
isSearching,
// @ts-expect-error
showSpinner,
// @ts-expect-error
getAvatarUrl,
// @ts-expect-error
getPresence,
// @ts-expect-error
onItemSelect,
// @ts-expect-error
contactSourceFilterRenderer: Filter,
// @ts-expect-error
sourceNodeRenderer,
// @ts-expect-error
onRefresh,
// @ts-expect-error
bottomNotice,
// @ts-expect-error
bottomNoticeHeight,
children,
// @ts-expect-error
currentSiteCode,
// @ts-expect-error
isMultipleSiteEnabled,
} = this.props;
// @ts-expect-error
const { refreshing, searchString, unfold, contentWidth, contentHeight } =
this.state;
const showRefresh = typeof onRefresh === 'function';
const refreshButton = showRefresh ? (
) : null;
return (
{refreshButton}
{showSpinner ?
: null}
{children}
);
}
}
// @ts-expect-error
ContactsView.propTypes = {
currentLocale: PropTypes.string.isRequired,
contactGroups: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
caption: PropTypes.string.isRequired,
contacts: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
type: PropTypes.string,
name: PropTypes.string,
extensionNumber: PropTypes.string,
email: PropTypes.string,
profileImageUrl: PropTypes.string,
presence: PropTypes.object,
contactStatus: PropTypes.string,
}),
).isRequired,
}),
).isRequired,
contactSourceNames: PropTypes.arrayOf(PropTypes.string).isRequired,
getAvatarUrl: PropTypes.func.isRequired,
getPresence: PropTypes.func.isRequired,
showSpinner: PropTypes.bool.isRequired,
currentSiteCode: PropTypes.string,
isMultipleSiteEnabled: PropTypes.bool,
searchSource: PropTypes.string,
searchString: PropTypes.string,
isSearching: PropTypes.bool,
onItemSelect: PropTypes.func,
onSearchContact: PropTypes.func,
contactSourceFilterRenderer: PropTypes.func,
sourceNodeRenderer: PropTypes.func,
onVisitPage: PropTypes.func,
onRefresh: PropTypes.func,
bottomNotice: PropTypes.func,
bottomNoticeHeight: PropTypes.number,
children: PropTypes.node,
};
// @ts-expect-error
ContactsView.defaultProps = {
searchSource: undefined,
searchString: undefined,
isSearching: false,
onItemSelect: undefined,
onSearchContact: undefined,
contactSourceFilterRenderer: ContactSourceFilter,
sourceNodeRenderer: undefined,
onVisitPage: undefined,
children: undefined,
onRefresh: undefined,
bottomNotice: undefined,
bottomNoticeHeight: 0,
currentSiteCode: '',
isMultipleSiteEnabled: false,
};
export default ContactsView;