Add publish to directory toggle in room settings (#2279)
authorAjay Bura <32841439+ajbura@users.noreply.github.com>
Thu, 20 Mar 2025 09:25:31 +0000 (20:25 +1100)
committerGitHub <noreply@github.com>
Thu, 20 Mar 2025 09:25:31 +0000 (20:25 +1100)
src/app/features/room-settings/general/General.tsx
src/app/features/room-settings/general/RoomPublish.tsx [new file with mode: 0644]
src/app/hooks/useRoomDirectoryVisibility.ts [new file with mode: 0644]

index 1033c300d63c1111a2515fa911717ff47675fd64..3d217f32a8d80ca99d12e51c17c61153c8352184 100644 (file)
@@ -8,6 +8,7 @@ import { RoomEncryption } from './RoomEncryption';
 import { RoomHistoryVisibility } from './RoomHistoryVisibility';
 import { RoomJoinRules } from './RoomJoinRules';
 import { RoomLocalAddresses, RoomPublishedAddresses } from './RoomAddress';
+import { RoomPublish } from './RoomPublish';
 import { RoomUpgrade } from './RoomUpgrade';
 
 type GeneralProps = {
@@ -43,6 +44,7 @@ export function General({ requestClose }: GeneralProps) {
                 <RoomJoinRules powerLevels={powerLevels} />
                 <RoomHistoryVisibility powerLevels={powerLevels} />
                 <RoomEncryption powerLevels={powerLevels} />
+                <RoomPublish powerLevels={powerLevels} />
               </Box>
               <Box direction="Column" gap="100">
                 <Text size="L400">Addresses</Text>
diff --git a/src/app/features/room-settings/general/RoomPublish.tsx b/src/app/features/room-settings/general/RoomPublish.tsx
new file mode 100644 (file)
index 0000000..d17f70e
--- /dev/null
@@ -0,0 +1,70 @@
+import React from 'react';
+import { Box, color, Spinner, Switch, Text } from 'folds';
+import { MatrixError } from 'matrix-js-sdk';
+import { SequenceCard } from '../../../components/sequence-card';
+import { SequenceCardStyle } from '../styles.css';
+import { SettingTile } from '../../../components/setting-tile';
+import { useRoom } from '../../../hooks/useRoom';
+import { useRoomDirectoryVisibility } from '../../../hooks/useRoomDirectoryVisibility';
+import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
+import { IPowerLevels, powerLevelAPI } from '../../../hooks/usePowerLevels';
+import { StateEvent } from '../../../../types/matrix/room';
+import { useMatrixClient } from '../../../hooks/useMatrixClient';
+
+type RoomPublishProps = {
+  powerLevels: IPowerLevels;
+};
+export function RoomPublish({ powerLevels }: RoomPublishProps) {
+  const mx = useMatrixClient();
+  const room = useRoom();
+  const userPowerLevel = powerLevelAPI.getPowerLevel(powerLevels, mx.getSafeUserId());
+  const canEditCanonical = powerLevelAPI.canSendStateEvent(
+    powerLevels,
+    StateEvent.RoomCanonicalAlias,
+    userPowerLevel
+  );
+
+  const { visibilityState, setVisibility } = useRoomDirectoryVisibility(room.roomId);
+
+  const [toggleState, toggleVisibility] = useAsyncCallback(setVisibility);
+
+  const loading =
+    visibilityState.status === AsyncStatus.Loading || toggleState.status === AsyncStatus.Loading;
+
+  return (
+    <SequenceCard
+      className={SequenceCardStyle}
+      variant="SurfaceVariant"
+      direction="Column"
+      gap="400"
+    >
+      <SettingTile
+        title="Publish To Directory"
+        after={
+          <Box gap="200" alignItems="Center">
+            {loading && <Spinner variant="Secondary" />}
+            {!loading && visibilityState.status === AsyncStatus.Success && (
+              <Switch
+                value={visibilityState.data}
+                onChange={toggleVisibility}
+                disabled={!canEditCanonical}
+              />
+            )}
+          </Box>
+        }
+      >
+        {visibilityState.status === AsyncStatus.Error && (
+          <Text style={{ color: color.Critical.Main }} size="T200">
+            {(visibilityState.error as MatrixError).message}
+          </Text>
+        )}
+
+        {toggleState.status === AsyncStatus.Error && (
+          <Text style={{ color: color.Critical.Main }} size="T200">
+            {(toggleState.error as MatrixError).message}
+          </Text>
+        )}
+      </SettingTile>
+    </SequenceCard>
+  );
+}
diff --git a/src/app/hooks/useRoomDirectoryVisibility.ts b/src/app/hooks/useRoomDirectoryVisibility.ts
new file mode 100644 (file)
index 0000000..6a60601
--- /dev/null
@@ -0,0 +1,35 @@
+import { useCallback, useEffect } from 'react';
+import { Visibility } from 'matrix-js-sdk';
+import { useAsyncCallback } from './useAsyncCallback';
+import { useMatrixClient } from './useMatrixClient';
+
+export const useRoomDirectoryVisibility = (roomId: string) => {
+  const mx = useMatrixClient();
+
+  const [visibilityState, loadVisibility] = useAsyncCallback(
+    useCallback(async () => {
+      const v = await mx.getRoomDirectoryVisibility(roomId);
+      return v.visibility === Visibility.Public;
+    }, [mx, roomId])
+  );
+
+  useEffect(() => {
+    loadVisibility();
+  }, [loadVisibility]);
+
+  const setVisibility = useCallback(
+    async (visibility: boolean) => {
+      await mx.setRoomDirectoryVisibility(
+        roomId,
+        visibility ? Visibility.Public : Visibility.Private
+      );
+      await loadVisibility();
+    },
+    [mx, roomId, loadVisibility]
+  );
+
+  return {
+    visibilityState,
+    setVisibility,
+  };
+};