import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import './SpaceAddExisting.scss'; import initMatrix from '../../../client/initMatrix'; import cons from '../../../client/state/cons'; import navigation from '../../../client/state/navigation'; import { joinRuleToIconSrc, getIdServer, genRoomVia } from '../../../util/matrixUtil'; import { Debounce } from '../../../util/common'; import Text from '../../atoms/text/Text'; import RawIcon from '../../atoms/system-icons/RawIcon'; import Button from '../../atoms/button/Button'; import IconButton from '../../atoms/button/IconButton'; import Checkbox from '../../atoms/button/Checkbox'; import Input from '../../atoms/input/Input'; import Spinner from '../../atoms/spinner/Spinner'; import RoomSelector from '../room-selector/RoomSelector'; import Dialog from '../dialog/Dialog'; import CrossIC from '../../../../public/res/ic/outlined/cross.svg'; import SearchIC from '../../../../public/res/ic/outlined/search.svg'; import { useStore } from '../../hooks/useStore'; function SpaceAddExistingContent({ roomId }) { const mountStore = useStore(roomId); const [debounce] = useState(new Debounce()); const [process, setProcess] = useState(null); const [allRoomIds, setAllRoomIds] = useState([]); const [selected, setSelected] = useState([]); const [searchIds, setSearchIds] = useState(null); const mx = initMatrix.matrixClient; const { spaces, rooms, directs, roomIdToParents } = initMatrix.roomList; useEffect(() => { const allIds = [...spaces, ...rooms, ...directs].filter( (rId) => rId !== roomId && !roomIdToParents.get(rId)?.has(roomId) ); setAllRoomIds(allIds); }, [roomId]); const toggleSelection = (rId) => { if (process !== null) return; const newSelected = [...selected]; const selectedIndex = newSelected.indexOf(rId); if (selectedIndex > -1) { newSelected.splice(selectedIndex, 1); setSelected(newSelected); return; } newSelected.push(rId); setSelected(newSelected); }; const handleAdd = async () => { setProcess(`Adding ${selected.length} items...`); const promises = selected.map((rId) => { const room = mx.getRoom(rId); const via = genRoomVia(room); if (via.length === 0) { via.push(getIdServer(rId)); } return mx.sendStateEvent( roomId, 'm.space.child', { auto_join: false, suggested: false, via, }, rId ); }); mountStore.setItem(true); await Promise.allSettled(promises); if (mountStore.getItem() !== true) return; const allIds = [...spaces, ...rooms, ...directs].filter( (rId) => rId !== roomId && !roomIdToParents.get(rId)?.has(roomId) && !selected.includes(rId) ); setAllRoomIds(allIds); setProcess(null); setSelected([]); }; const handleSearch = (ev) => { const term = ev.target.value.toLocaleLowerCase().replace(/\s/g, ''); if (term === '') { setSearchIds(null); return; } debounce._(() => { const searchedIds = allRoomIds.filter((rId) => { let name = mx.getRoom(rId)?.name; if (!name) return false; name = name.normalize('NFKC').toLocaleLowerCase().replace(/\s/g, ''); return name.includes(term); }); setSearchIds(searchedIds); }, 200)(); }; const handleSearchClear = (ev) => { const btn = ev.currentTarget; btn.parentElement.searchInput.value = ''; setSearchIds(null); }; return ( <>
{ ev.preventDefault(); }} > {searchIds?.length === 0 && No results found} {(searchIds || allRoomIds).map((rId) => { const room = mx.getRoom(rId); let imageSrc = room.getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 24, 24, 'crop') || null; if (imageSrc === null) imageSrc = room.getAvatarUrl(mx.baseUrl, 24, 24, 'crop') || null; const parentSet = roomIdToParents.get(rId); const parentNames = parentSet ? [...parentSet].map((parentId) => mx.getRoom(parentId).name) : undefined; const parents = parentNames ? parentNames.join(', ') : null; const handleSelect = () => toggleSelection(rId); return ( } /> ); })} {selected.length !== 0 && (
{process && } {process || `${selected.length} item selected`} {!process && ( )}
)} ); } SpaceAddExistingContent.propTypes = { roomId: PropTypes.string.isRequired, }; function useVisibilityToggle() { const [roomId, setRoomId] = useState(null); useEffect(() => { const handleOpen = (rId) => setRoomId(rId); navigation.on(cons.events.navigation.SPACE_ADDEXISTING_OPENED, handleOpen); return () => { navigation.removeListener(cons.events.navigation.SPACE_ADDEXISTING_OPENED, handleOpen); }; }, []); const requestClose = () => setRoomId(null); return [roomId, requestClose]; } function SpaceAddExisting() { const [roomId, requestClose] = useVisibilityToggle(); const mx = initMatrix.matrixClient; const room = mx.getRoom(roomId); return ( {roomId && room.name} — add existing rooms } contentOptions={} onRequestClose={requestClose} > {roomId ? :
}
); } export default SpaceAddExisting;