// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { FunctionComponent, useEffect, useMemo, useRef, useState, } from 'react'; import Measure, { MeasuredComponentProps } from 'react-measure'; import { LocalizerType } from '../../../../types/Util'; import { assert } from '../../../../util/assert'; import { getOwn } from '../../../../util/getOwn'; import { missingCaseError } from '../../../../util/missingCaseError'; import { filterAndSortConversationsByTitle } from '../../../../util/filterAndSortConversations'; import { ConversationType } from '../../../../state/ducks/conversations'; import { ModalHost } from '../../../ModalHost'; import { ContactPills } from '../../../ContactPills'; import { ContactPill } from '../../../ContactPill'; import { ConversationList, Row, RowType } from '../../../ConversationList'; import { ContactCheckboxDisabledReason } from '../../../conversationList/ContactCheckbox'; import { Button, ButtonVariant } from '../../../Button'; type PropsType = { candidateContacts: ReadonlyArray; confirmAdds: () => void; contactLookup: Record; conversationIdsAlreadyInGroup: Set; i18n: LocalizerType; maxGroupSize: number; onClose: () => void; removeSelectedContact: (_: string) => void; searchTerm: string; selectedContacts: ReadonlyArray; setCantAddContactForModal: ( _: Readonly ) => void; setSearchTerm: (_: string) => void; toggleSelectedContact: (conversationId: string) => void; }; // TODO: This should use . See DESKTOP-1038. export const ChooseGroupMembersModal: FunctionComponent = ({ candidateContacts, confirmAdds, contactLookup, conversationIdsAlreadyInGroup, i18n, maxGroupSize, onClose, removeSelectedContact, searchTerm, selectedContacts, setCantAddContactForModal, setSearchTerm, toggleSelectedContact, }) => { const inputRef = useRef(null); const numberOfContactsAlreadyInGroup = conversationIdsAlreadyInGroup.size; const hasSelectedMaximumNumberOfContacts = selectedContacts.length + numberOfContactsAlreadyInGroup >= maxGroupSize; const selectedConversationIdsSet: Set = useMemo( () => new Set(selectedContacts.map(contact => contact.id)), [selectedContacts] ); const canContinue = Boolean(selectedContacts.length); const [filteredContacts, setFilteredContacts] = useState( filterAndSortConversationsByTitle(candidateContacts, '') ); const normalizedSearchTerm = searchTerm.trim(); useEffect(() => { const timeout = setTimeout(() => { setFilteredContacts( filterAndSortConversationsByTitle( candidateContacts, normalizedSearchTerm ) ); }, 200); return () => { clearTimeout(timeout); }; }, [candidateContacts, normalizedSearchTerm, setFilteredContacts]); const rowCount = filteredContacts.length; const getRow = (index: number): undefined | Row => { const contact = filteredContacts[index]; if (!contact) { return undefined; } const isSelected = selectedConversationIdsSet.has(contact.id); const isAlreadyInGroup = conversationIdsAlreadyInGroup.has(contact.id); let disabledReason: undefined | ContactCheckboxDisabledReason; if (isAlreadyInGroup) { disabledReason = ContactCheckboxDisabledReason.AlreadyAdded; } else if (hasSelectedMaximumNumberOfContacts && !isSelected) { disabledReason = ContactCheckboxDisabledReason.MaximumContactsSelected; } else if (!contact.isGroupV2Capable) { disabledReason = ContactCheckboxDisabledReason.NotCapable; } return { type: RowType.ContactCheckbox, contact, isChecked: isSelected || isAlreadyInGroup, disabledReason, }; }; return (
); }; function shouldNeverBeCalled(..._args: ReadonlyArray): unknown { assert(false, 'This should never be called. Doing nothing'); }