import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { useAtomValue } from 'jotai'; import './SpaceAddExisting.scss'; import cons from '../../../client/state/cons'; import navigation from '../../../client/state/navigation'; import { joinRuleToIconSrc, getIdServer } 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'; import { roomToParentsAtom } from '../../state/room/roomToParents'; import { useDirects, useRooms, useSpaces } from '../../state/hooks/roomList'; import { allRoomsAtom } from '../../state/room-list/roomList'; import { mDirectAtom } from '../../state/mDirectList'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { getViaServers } from '../../plugins/via-servers'; import { rateLimitedActions } from '../../utils/matrix'; import { useAlive } from '../../hooks/useAlive'; function SpaceAddExistingContent({ roomId, spaces: onlySpaces }) { const alive = useAlive(); 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 = useMatrixClient(); const roomIdToParents = useAtomValue(roomToParentsAtom); const mDirects = useAtomValue(mDirectAtom); const spaces = useSpaces(mx, allRoomsAtom); const rooms = useRooms(mx, allRoomsAtom, mDirects); const directs = useDirects(mx, allRoomsAtom, mDirects); useEffect(() => { const roomIds = onlySpaces ? [...spaces] : [...rooms, ...directs]; const allIds = roomIds.filter( (rId) => rId !== roomId && !roomIdToParents.get(rId)?.has(roomId) ); setAllRoomIds(allIds); }, [spaces, rooms, directs, roomIdToParents, roomId, onlySpaces]); 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...`); await rateLimitedActions(selected, async (rId) => { const room = mx.getRoom(rId); const via = getViaServers(room); if (via.length === 0) { via.push(getIdServer(rId)); } await mx.sendStateEvent( roomId, 'm.space.child', { auto_join: false, suggested: false, via, }, rId ); }); if (!alive()) return; const roomIds = onlySpaces ? [...spaces] : [...rooms, ...directs]; const allIds = roomIds.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 ( <>
{searchIds?.length === 0 &&