import { Button, Column, Dialog, ModalContext } from '@8base/boost'; import { ApolloClient, ApolloQueryResult, FetchPolicy } from 'apollo-client'; import debounce from 'lodash/debounce'; import React from 'react'; import { compose, withApollo } from 'react-apollo'; import { ChatContext, IChatContext, withContext } from 'context'; import { DialogForm } from 'shared/components'; import ChannelsBrowser from 'shared/components/channels-browser'; import { ChannelMemberCreateDocument, ChannelMemberCreateMutation, ChannelMemberCreateMutationVariables, ChannelsSearchDocument, ChannelsSearchQuery, ChannelsSearchQueryVariables, UserChannelsPreviewDocument, } from 'shared/graphql/__generated__'; import { log, makeCancelable } from 'shared/utils'; import { IOption } from 'types'; import { getOperationName } from 'apollo-link'; import cssUtils from '../../../styles/utilities.css'; // -- TYPES interface IChannelsSearchDialogProps extends Pick { client: ApolloClient; } interface IDialogContentProps extends IChannelsSearchDialogProps {} interface IDialogContentState { data: { channel?: IOption | null; }; searchText: string; channelsList: ChannelsSearchQuery['channelsList']; loadingOptions: boolean; submitting: boolean; } // -- CONSTANTS export const CHANNELS_SEARCH_DIALOG_ID = 'CHANNELS_SEARCH_DIALOG_ID'; // -- COMPONENTS const cnSelectBrowser = { list: cssUtils['u-dialog-browser-list'], }; class DialogContent extends React.Component { static contextType = ModalContext; private onSearchDebounced: DialogContent['onSearch']; private currentRequest?: ReturnType; constructor(props: IDialogContentProps) { super(props); this.state = { data: { channel: null, }, searchText: '', channelsList: { items: [], }, loadingOptions: false, submitting: false, }; this.onSearchDebounced = debounce(this.onSearch, 200); } componentDidMount() { this.fetchChannels(this.state.searchText, 'network-only'); } componentWillUnmount() { this.cancelCurrentRequest(); } render() { const { data, searchText, channelsList, loadingOptions, submitting } = this.state; const selectedChannelId = data.channel && data.channel.value; const disabled = !selectedChannelId; return ( ); } private onSubmit = async (e: any) => { e.preventDefault(); const selectedChannelId = this.state.data.channel && this.state.data.channel.value; const { user, client } = this.props; if (!user || !selectedChannelId || this.state.submitting) { return; } this.setState({ submitting: true, }); let response: { data: ChannelMemberCreateMutation } | undefined; try { response = await client.mutate< ChannelMemberCreateMutation, ChannelMemberCreateMutationVariables >({ mutation: ChannelMemberCreateDocument, variables: { data: { channel: { connect: { id: selectedChannelId }, }, user: { connect: { id: user.id }, }, }, }, refetchQueries: [getOperationName(UserChannelsPreviewDocument) as string], }); } catch (e) { log('error', e); } this.setState({ submitting: false, }); if (!response) { return; } this.props.setChannel({ channelIdentityId: response.data.channelMemberCreate.id as string, }); this.closeModal(); }; private closeModal = () => { this.context.closeModal(CHANNELS_SEARCH_DIALOG_ID); }; private onItemSelect = (option: IOption) => { this.onSearchDebounced(''); this.setState({ data: { channel: option, }, searchText: '', }); }; private onInputChange = (val: string, { action }: { action: string }) => { if (action !== 'input-change') { return; } this.setState({ searchText: val, }); this.onSearchDebounced(val); }; private onSearch = (text: string) => { this.cancelCurrentRequest(); this.fetchChannels(text); }; private fetchChannels(text: string, fetchPolicy?: FetchPolicy) { const userId = this.props.user ? this.props.user.id : ''; this.setState({ loadingOptions: true, }); this.currentRequest = makeCancelable( this.props.client.query({ query: ChannelsSearchDocument, variables: { first: 10, searchText: text, userId, }, fetchPolicy, }), ); (this.currentRequest.promise as Promise>) .then(({ data }) => { this.setState({ channelsList: data.channelsList, loadingOptions: false, }); }) .catch(() => {}); } private cancelCurrentRequest() { if (this.currentRequest) { this.currentRequest.cancel(); } } } // -- MAIN function ChannelsSearchDialog(props: IChannelsSearchDialogProps) { return ( ); } ChannelsSearchDialog.id = CHANNELS_SEARCH_DIALOG_ID; export default compose( withApollo, withContext({ context: ChatContext, keys: ['user', 'setChannel'] }), )(ChannelsSearchDialog);