import React, { MouseEventHandler, forwardRef, useMemo, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Avatar, Box, Button, Icon, IconButton, Icons, Menu, MenuItem, PopOut, RectCords, Text, config, toRem, } from 'folds'; import { useVirtualizer } from '@tanstack/react-virtual'; import { useAtom, useAtomValue } from 'jotai'; import FocusTrap from 'focus-trap-react'; import { factoryRoomIdByActivity, factoryRoomIdByAtoZ } from '../../../utils/sort'; import { NavButton, NavCategory, NavCategoryHeader, NavEmptyCenter, NavEmptyLayout, NavItem, NavItemContent, NavLink, } from '../../../components/nav'; import { getExplorePath, getHomeRoomPath, getHomeSearchPath } from '../../pathUtils'; import { getCanonicalAliasOrRoomId } from '../../../utils/matrix'; import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom'; import { useHomeSearchSelected } from '../../../hooks/router/useHomeSelected'; import { useHomeRooms } from './useHomeRooms'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { VirtualTile } from '../../../components/virtualizer'; import { RoomNavCategoryButton, RoomNavItem } from '../../../features/room-nav'; import { muteChangesAtom } from '../../../state/room-list/mutedRoomList'; import { makeNavCategoryId } from '../../../state/closedNavCategories'; import { roomToUnreadAtom } from '../../../state/room/roomToUnread'; import { useCategoryHandler } from '../../../hooks/useCategoryHandler'; import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper'; import { openCreateRoom, openJoinAlias } from '../../../../client/action/navigation'; import { PageNav, PageNavHeader, PageNavContent } from '../../../components/page'; import { useRoomsUnread } from '../../../state/hooks/unread'; import { markAsRead } from '../../../../client/action/notifications'; import { useClosedNavCategoriesAtom } from '../../../state/hooks/closedNavCategories'; import { stopPropagation } from '../../../utils/keyboard'; import { useSetting } from '../../../state/hooks/settings'; import { settingsAtom } from '../../../state/settings'; type HomeMenuProps = { requestClose: () => void; }; const HomeMenu = forwardRef(({ requestClose }, ref) => { const orphanRooms = useHomeRooms(); const [hideActivity] = useSetting(settingsAtom, 'hideActivity'); const unread = useRoomsUnread(orphanRooms, roomToUnreadAtom); const mx = useMatrixClient(); const handleMarkAsRead = () => { if (!unread) return; orphanRooms.forEach((rId) => markAsRead(mx, rId, hideActivity)); requestClose(); }; const handleJoinAddress = () => { openJoinAlias(); requestClose(); }; return ( } radii="300" aria-disabled={!unread} > Mark as Read } > Join with Address ); }); function HomeHeader() { const [menuAnchor, setMenuAnchor] = useState(); const handleOpenMenu: MouseEventHandler = (evt) => { const cords = evt.currentTarget.getBoundingClientRect(); setMenuAnchor((currentState) => { if (currentState) return undefined; return cords; }); }; return ( <> Home setMenuAnchor(undefined), clickOutsideDeactivates: true, isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', escapeDeactivates: stopPropagation, }} > setMenuAnchor(undefined)} /> } /> ); } function HomeEmpty() { const navigate = useNavigate(); return ( } title={ No Rooms } content={ You do not have any rooms yet. } options={ <> } /> ); } const DEFAULT_CATEGORY_ID = makeNavCategoryId('home', 'room'); export function Home() { const mx = useMatrixClient(); useNavToActivePathMapper('home'); const scrollRef = useRef(null); const rooms = useHomeRooms(); const muteChanges = useAtomValue(muteChangesAtom); const mutedRooms = muteChanges.added; const roomToUnread = useAtomValue(roomToUnreadAtom); const selectedRoomId = useSelectedRoom(); const searchSelected = useHomeSearchSelected(); const noRoomToDisplay = rooms.length === 0; const [closedCategories, setClosedCategories] = useAtom(useClosedNavCategoriesAtom()); const sortedRooms = useMemo(() => { const items = Array.from(rooms).sort( closedCategories.has(DEFAULT_CATEGORY_ID) ? factoryRoomIdByActivity(mx) : factoryRoomIdByAtoZ(mx) ); if (closedCategories.has(DEFAULT_CATEGORY_ID)) { return items.filter((rId) => roomToUnread.has(rId) || rId === selectedRoomId); } return items; }, [mx, rooms, closedCategories, roomToUnread, selectedRoomId]); const virtualizer = useVirtualizer({ count: sortedRooms.length, getScrollElement: () => scrollRef.current, estimateSize: () => 38, overscan: 10, }); const handleCategoryClick = useCategoryHandler(setClosedCategories, (categoryId) => closedCategories.has(categoryId) ); return ( {noRoomToDisplay ? ( ) : ( openCreateRoom()}> Create Room openJoinAlias()}> Join with Address Message Search Rooms
{virtualizer.getVirtualItems().map((vItem) => { const roomId = sortedRooms[vItem.index]; const room = mx.getRoom(roomId); if (!room) return null; const selected = selectedRoomId === roomId; return ( ); })}
)}
); }