Add ability to manage room history visibility
authorAjay Bura <ajbura@gmail.com>
Sat, 1 Jan 2022 10:57:36 +0000 (16:27 +0530)
committerAjay Bura <ajbura@gmail.com>
Sat, 1 Jan 2022 10:57:36 +0000 (16:27 +0530)
Signed-off-by: Ajay Bura <ajbura@gmail.com>
src/app/molecules/room-aliases/RoomAliases.jsx
src/app/molecules/room-history-visibility/RoomHistoryVisibility.jsx [new file with mode: 0644]
src/app/molecules/room-history-visibility/RoomHistoryVisibility.scss [new file with mode: 0644]
src/app/organisms/room/RoomSettings.jsx

index f8896eb1c3e07d00d52280bf05c9a4dc04c7d0bf..2093ab77a39653b3c64de5c929faf9565d166aa3 100644 (file)
@@ -12,8 +12,8 @@ import Button from '../../atoms/button/Button';
 import Input from '../../atoms/input/Input';
 import Checkbox from '../../atoms/button/Checkbox';
 import Toggle from '../../atoms/button/Toggle';
-import { MenuItem, MenuHeader } from '../../atoms/context-menu/ContextMenu';
-import SettingTile from '../../molecules/setting-tile/SettingTile';
+import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
+import SettingTile from '../setting-tile/SettingTile';
 
 import { useStore } from '../../hooks/useStore';
 
diff --git a/src/app/molecules/room-history-visibility/RoomHistoryVisibility.jsx b/src/app/molecules/room-history-visibility/RoomHistoryVisibility.jsx
new file mode 100644 (file)
index 0000000..766f765
--- /dev/null
@@ -0,0 +1,99 @@
+import React, { useState, useEffect, useCallback } from 'react';
+import PropTypes from 'prop-types';
+import './RoomHistoryVisibility.scss';
+
+import initMatrix from '../../../client/initMatrix';
+
+import Text from '../../atoms/text/Text';
+import RadioButton from '../../atoms/button/RadioButton';
+import { MenuItem } from '../../atoms/context-menu/ContextMenu';
+
+const visibility = {
+  WORLD_READABLE: 'world_readable',
+  SHARED: 'shared',
+  INVITED: 'invited',
+  JOINED: 'joined',
+};
+
+const items = [{
+  iconSrc: null,
+  text: 'World readable (anyone can read)',
+  type: visibility.WORLD_READABLE,
+}, {
+  iconSrc: null,
+  text: 'Member shared (since the point in time of selecting this option)',
+  type: visibility.SHARED,
+}, {
+  iconSrc: null,
+  text: 'Member invited (since they were invited)',
+  type: visibility.INVITED,
+}, {
+  iconSrc: null,
+  text: 'Member joined (since they joined)',
+  type: visibility.JOINED,
+}];
+
+function setHistoryVisibility(roomId, type) {
+  const mx = initMatrix.matrixClient;
+
+  return mx.sendStateEvent(
+    roomId, 'm.room.history_visibility',
+    {
+      history_visibility: type,
+    },
+  );
+}
+
+function useVisibility(roomId) {
+  const mx = initMatrix.matrixClient;
+  const room = mx.getRoom(roomId);
+
+  const [activeType, setActiveType] = useState(room.getHistoryVisibility());
+  useEffect(() => setActiveType(room.getHistoryVisibility()), [roomId]);
+
+  const setVisibility = useCallback((item) => {
+    if (item.type === activeType.type) return;
+    setActiveType(item.type);
+    setHistoryVisibility(roomId, item.type);
+  }, [activeType, roomId]);
+
+  return [activeType, setVisibility];
+}
+
+function RoomHistoryVisibility({ roomId }) {
+  const [activeType, setVisibility] = useVisibility(roomId);
+  const mx = initMatrix.matrixClient;
+  const userId = mx.getUserId();
+  const room = mx.getRoom(roomId);
+  const { currentState } = room;
+
+  const canChange = currentState.maySendStateEvent('m.room.history_visibility', userId);
+
+  return (
+    <div className="room-history-visibility">
+      {
+        items.map((item) => (
+          <MenuItem
+            variant={activeType === item.type ? 'positive' : 'surface'}
+            key={item.type}
+            iconSrc={item.iconSrc}
+            onClick={() => setVisibility(item)}
+            disabled={(!canChange)}
+          >
+            <Text varient="b1">
+              <span>{item.text}</span>
+              <RadioButton isActive={activeType === item.type} />
+            </Text>
+          </MenuItem>
+        ))
+      }
+      <Text variant="b3">Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.</Text>
+    </div>
+  );
+}
+
+RoomHistoryVisibility.propTypes = {
+  roomId: PropTypes.string.isRequired,
+};
+
+export default RoomHistoryVisibility;
diff --git a/src/app/molecules/room-history-visibility/RoomHistoryVisibility.scss b/src/app/molecules/room-history-visibility/RoomHistoryVisibility.scss
new file mode 100644 (file)
index 0000000..b9e0a2c
--- /dev/null
@@ -0,0 +1,25 @@
+@use '../../partials/flex';
+@use '../../partials/dir';
+@use '../../partials/text';
+
+.room-history-visibility {
+  & .context-menu__item .text {
+    margin: 0 !important;
+    @extend .cp-fx__item-one;
+    @extend .cp-fx__row--s-c;
+    
+    & span:first-child {
+      @extend .cp-fx__item-one;
+      @extend .cp-txt__ellipsis;
+    }
+    
+    & .radio-btn {
+      @include dir.side(margin, var(--sp-tight), 0);
+    }
+  }
+
+  & > .text {
+    margin: var(--sp-normal);
+    margin-top: var(--sp-ultra-tight);
+  }
+}
\ No newline at end of file
index 8c7323bd80b733e22fe405a5668e278a597843c9..91fd11e1bddd3a8fd8e240e832a06f20b5c54999 100644 (file)
@@ -17,6 +17,7 @@ import RoomProfile from '../../molecules/room-profile/RoomProfile';
 import RoomNotification from '../../molecules/room-notification/RoomNotification';
 import RoomVisibility from '../../molecules/room-visibility/RoomVisibility';
 import RoomAliases from '../../molecules/room-aliases/RoomAliases';
+import RoomHistoryVisibility from '../../molecules/room-history-visibility/RoomHistoryVisibility';
 
 import SettingsIC from '../../../../public/res/ic/outlined/settings.svg';
 import SearchIC from '../../../../public/res/ic/outlined/search.svg';
@@ -28,25 +29,33 @@ import LeaveArrowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
 
 import { useForceUpdate } from '../../hooks/useForceUpdate';
 
+const tabText = {
+  GENERAL: 'General',
+  SEARCH: 'Search',
+  PERMISSIONS: 'Permissions',
+  SECURITY: 'Security',
+  ADVANCED: 'Advanced',
+};
+
 const tabItems = [{
   iconSrc: SettingsIC,
-  text: 'General',
+  text: tabText.GENERAL,
   disabled: false,
 }, {
   iconSrc: SearchIC,
-  text: 'Search',
+  text: tabText.SEARCH,
   disabled: false,
 }, {
   iconSrc: ShieldUserIC,
-  text: 'Permissions',
+  text: tabText.PERMISSIONS,
   disabled: false,
 }, {
   iconSrc: LockIC,
-  text: 'Security',
+  text: tabText.SECURITY,
   disabled: false,
 }, {
   iconSrc: InfoIC,
-  text: 'Advanced',
+  text: tabText.ADVANCED,
   disabled: false,
 }];
 
@@ -87,6 +96,20 @@ GeneralSettings.propTypes = {
   roomId: PropTypes.string.isRequired,
 };
 
+function SecuritySettings({ roomId }) {
+  return (
+    <>
+      <div className="room-settings__card">
+        <MenuHeader>Message history visibility (Who can read history)</MenuHeader>
+        <RoomHistoryVisibility roomId={roomId} />
+      </div>
+    </>
+  );
+}
+SecuritySettings.propTypes = {
+  roomId: PropTypes.string.isRequired,
+};
+
 function RoomSettings({ roomId }) {
   const [, forceUpdate] = useForceUpdate();
   const [selectedTab, setSelectedTab] = useState(tabItems[0]);
@@ -127,7 +150,8 @@ function RoomSettings({ roomId }) {
             onSelect={handleTabChange}
           />
           <div className="room-settings__cards-wrapper">
-            {selectedTab.text === tabItems[0].text && <GeneralSettings roomId={roomId} />}
+            {selectedTab.text === tabText.GENERAL && <GeneralSettings roomId={roomId} />}
+            {selectedTab.text === tabText.SECURITY && <SecuritySettings roomId={roomId} />}
           </div>
         </div>
       </ScrollView>