import React, { useMemo, useState } from 'react'; import { useAtomValue } from 'jotai'; import { Avatar, Box, config, Icon, IconButton, Icons, IconSrc, MenuItem, Text } from 'folds'; import { JoinRule } from 'matrix-js-sdk'; import { PageNav, PageNavContent, PageNavHeader, PageRoot } from '../../components/page'; import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { mxcUrlToHttp } from '../../utils/matrix'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { useRoomAvatar, useRoomJoinRule, useRoomName } from '../../hooks/useRoomMeta'; import { mDirectAtom } from '../../state/mDirectList'; import { RoomAvatar, RoomIcon } from '../../components/room-avatar'; import { General } from './general'; import { Members } from '../common-settings/members'; import { EmojisStickers } from '../common-settings/emojis-stickers'; import { Permissions } from './permissions'; import { RoomSettingsPage } from '../../state/roomSettings'; import { useRoom } from '../../hooks/useRoom'; import { DeveloperTools } from '../common-settings/developer-tools'; import { ExportRoomHistory } from './ExportRoomHistory'; import { RoomActivityLog } from './RoomActivityLog'; import { RoomServerACL } from './RoomServerACL'; import { RoomInsights } from './RoomInsights'; import { PolicyListViewer } from './PolicyListViewer'; import { usePowerLevels, readPowerLevel } from '../../hooks/usePowerLevels'; import { useRoomCreators } from '../../hooks/useRoomCreators'; import { StateEvent } from '../../../types/matrix/room'; type RoomSettingsMenuItem = { page: RoomSettingsPage; name: string; icon: IconSrc; }; const BASE_MENU_ITEMS: RoomSettingsMenuItem[] = [ { page: RoomSettingsPage.GeneralPage, name: 'General', icon: Icons.Setting, }, { page: RoomSettingsPage.MembersPage, name: 'Members', icon: Icons.User, }, { page: RoomSettingsPage.PermissionsPage, name: 'Permissions', icon: Icons.Lock, }, { page: RoomSettingsPage.EmojisStickersPage, name: 'Emojis & Stickers', icon: Icons.Smile, }, { page: RoomSettingsPage.DeveloperToolsPage, name: 'Developer Tools', icon: Icons.Terminal, }, { page: RoomSettingsPage.ExportPage, name: 'Export', icon: Icons.Download, }, { page: RoomSettingsPage.ActivityLogPage, name: 'Activity', icon: Icons.RecentClock, }, { page: RoomSettingsPage.InsightsPage, name: 'Insights', icon: Icons.Info, }, ]; const SERVER_ACL_MENU_ITEM: RoomSettingsMenuItem = { page: RoomSettingsPage.ServerACLPage, name: 'Server ACL', icon: Icons.Shield, }; const POLICY_LISTS_MENU_ITEM: RoomSettingsMenuItem = { page: RoomSettingsPage.PolicyListsPage, name: 'Policy Lists', icon: Icons.NoEntry, }; function useRoomSettingsMenuItems( canSeeServerACL: boolean, canSeePolicyLists: boolean, ): RoomSettingsMenuItem[] { return useMemo(() => { const items = [...BASE_MENU_ITEMS]; if (canSeeServerACL) items.push(SERVER_ACL_MENU_ITEM); if (canSeePolicyLists) items.push(POLICY_LISTS_MENU_ITEM); return items; }, [canSeeServerACL, canSeePolicyLists]); } type RoomSettingsProps = { initialPage?: RoomSettingsPage; requestClose: () => void; }; export function RoomSettings({ initialPage, requestClose }: RoomSettingsProps) { const room = useRoom(); const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const mDirects = useAtomValue(mDirectAtom); const roomAvatar = useRoomAvatar(room, mDirects.has(room.roomId)); const roomName = useRoomName(room); const joinRuleContent = useRoomJoinRule(room); const avatarUrl = roomAvatar ? (mxcUrlToHttp(mx, roomAvatar, useAuthentication, 96, 96, 'crop') ?? undefined) : undefined; // Power level check: show Server ACL menu item to anyone who can read the state // (i.e. has at least state_default power level, or a custom ACL event power). // We show it to all users at or above the required power level; read-only view // for those who cannot edit. const powerLevels = usePowerLevels(room); const creators = useRoomCreators(room); const myUserId = mx.getSafeUserId(); const myPL = readPowerLevel.user(powerLevels, myUserId); const requiredPL = readPowerLevel.state(powerLevels, StateEvent.RoomServerAcl); // Show the menu item if user meets the power level OR is a room creator. const canSeeServerACL = myPL >= requiredPL || creators.has(myUserId); // Show Policy Lists to admins (power level 50+) or creators. const canSeePolicyLists = myPL >= 50 || creators.has(myUserId); const screenSize = useScreenSizeContext(); const [activePage, setActivePage] = useState(() => { if (initialPage) return initialPage; return screenSize === ScreenSize.Mobile ? undefined : RoomSettingsPage.GeneralPage; }); const menuItems = useRoomSettingsMenuItems(canSeeServerACL, canSeePolicyLists); const handlePageRequestClose = () => { if (screenSize === ScreenSize.Mobile) { setActivePage(undefined); return; } requestClose(); }; return ( ( )} /> {roomName} {screenSize === ScreenSize.Mobile && ( )}
{menuItems.map((item) => ( } onClick={() => setActivePage(item.page)} > {item.name} ))}
) } > {activePage === RoomSettingsPage.GeneralPage && ( )} {activePage === RoomSettingsPage.MembersPage && ( )} {activePage === RoomSettingsPage.PermissionsPage && ( )} {activePage === RoomSettingsPage.EmojisStickersPage && ( )} {activePage === RoomSettingsPage.DeveloperToolsPage && ( )} {activePage === RoomSettingsPage.ExportPage && ( )} {activePage === RoomSettingsPage.ActivityLogPage && ( )} {activePage === RoomSettingsPage.ServerACLPage && ( )} {activePage === RoomSettingsPage.InsightsPage && ( )} {activePage === RoomSettingsPage.PolicyListsPage && ( )}
); }