Add option to kick user in profile viewer
authorAjay Bura <ajbura@gmail.com>
Wed, 12 Jan 2022 12:56:52 +0000 (18:26 +0530)
committerAjay Bura <ajbura@gmail.com>
Wed, 12 Jan 2022 12:56:52 +0000 (18:26 +0530)
Signed-off-by: Ajay Bura <ajbura@gmail.com>
src/app/organisms/profile-viewer/ProfileViewer.jsx
src/app/organisms/profile-viewer/ProfileViewer.scss
src/client/action/room.js

index 87f085d84d8f4043c633095d8f2ff22428835bde..e6b3a839d78d141f662502c229d0268f7f50ef27 100644 (file)
@@ -17,6 +17,7 @@ import colorMXID from '../../../util/colorMXID';
 import Text from '../../atoms/text/Text';
 import Chip from '../../atoms/chip/Chip';
 import IconButton from '../../atoms/button/IconButton';
+import Input from '../../atoms/input/Input';
 import Avatar from '../../atoms/avatar/Avatar';
 import Button from '../../atoms/button/Button';
 import PowerLevelSelector from '../../molecules/power-level-selector/PowerLevelSelector';
@@ -29,6 +30,45 @@ import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 
 import { useForceUpdate } from '../../hooks/useForceUpdate';
 
+function ModerationTools({
+  roomId, userId,
+}) {
+  const mx = initMatrix.matrixClient;
+  const room = mx.getRoom(roomId);
+  const roomMember = room.getMember(userId);
+
+  const myPowerLevel = room.getMember(mx.getUserId()).powerLevel;
+  const powerLevel = roomMember?.powerLevel || 0;
+  const canIKick = (
+    roomMember?.membership === 'join'
+    && room.currentState.hasSufficientPowerLevelFor('kick', myPowerLevel)
+    && powerLevel < myPowerLevel
+  );
+
+  const handleKick = (e) => {
+    e.preventDefault();
+    const kickReason = e.target.elements['kick-reason']?.value.trim();
+    roomActions.kick(roomId, userId, kickReason !== '' ? kickReason : undefined);
+  };
+
+  return (
+    <div className="moderation-tools">
+      {canIKick && (
+        <>
+          <form onSubmit={handleKick}>
+            <Input label="Kick reason" name="kick-reason" />
+            <Button type="submit">Kick</Button>
+          </form>
+        </>
+      )}
+    </div>
+  );
+}
+ModerationTools.propTypes = {
+  roomId: PropTypes.string.isRequired,
+  userId: PropTypes.string.isRequired,
+};
+
 function SessionInfo({ userId }) {
   const [devices, setDevices] = useState(null);
   const mx = initMatrix.matrixClient;
@@ -257,25 +297,30 @@ function useToggleDialog() {
   return [isOpen, roomId, userId, closeDialog, afterClose];
 }
 
-function useRerenderOnRoleChange(roomId, userId) {
+function useRerenderOnProfileChange(roomId, userId) {
   const mx = initMatrix.matrixClient;
   const [, forceUpdate] = useForceUpdate();
   useEffect(() => {
-    const handlePowerLevelChange = (mEvent, member) => {
-      if (mEvent.getRoomId() === roomId && member.userId === userId) {
+    const handleProfileChange = (mEvent, member) => {
+      if (
+        mEvent.getRoomId() === roomId
+        && (member.userId === userId || member.userId === mx.getUserId())
+      ) {
         forceUpdate();
       }
     };
-    mx.on('RoomMember.powerLevel', handlePowerLevelChange);
+    mx.on('RoomMember.powerLevel', handleProfileChange);
+    mx.on('RoomMember.membership', handleProfileChange);
     return () => {
-      mx.removeListener('RoomMember.powerLevel', handlePowerLevelChange);
+      mx.removeListener('RoomMember.powerLevel', handleProfileChange);
+      mx.removeListener('RoomMember.membership', handleProfileChange);
     };
   }, [roomId, userId]);
 }
 
 function ProfileViewer() {
   const [isOpen, roomId, userId, closeDialog, handleAfterClose] = useToggleDialog();
-  useRerenderOnRoleChange(roomId, userId);
+  useRerenderOnProfileChange(roomId, userId);
 
   const mx = initMatrix.matrixClient;
   const room = mx.getRoom(roomId);
@@ -288,8 +333,8 @@ function ProfileViewer() {
   }
 
   const renderProfile = () => {
-    const avatarMxc = roomMember.getMxcAvatarUrl?.() || mx.getMember(userId).avatarUrl;
-    const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null;
+    const avatarMxc = roomMember?.getMxcAvatarUrl?.() || mx.getUser(userId).avatarUrl;
+    const avatarUrl = (avatarMxc && avatarMxc !== 'null') ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null;
 
     const powerLevel = roomMember.powerLevel || 0;
     const myPowerLevel = room.getMember(mx.getUserId())?.powerLevel || 0;
@@ -344,13 +389,10 @@ function ProfileViewer() {
             </Button>
           </div>
         </div>
+        <ModerationTools roomId={roomId} userId={userId} />
         <SessionInfo userId={userId} />
         { userId !== mx.getUserId() && (
-          <ProfileFooter
-            roomId={roomId}
-            userId={userId}
-            onRequestClose={closeDialog}
-          />
+          <ProfileFooter roomId={roomId} userId={userId} onRequestClose={closeDialog} />
         )}
       </div>
     );
index 230c8db7e012ee727448461dabd918bef5e3b5c8..b8c464267c92ff7ba7970a99e8128f28283931c1 100644 (file)
@@ -1,3 +1,4 @@
+@use '../../partials/flex';
 @use '../../partials/dir';
 
 .profile-viewer__dialog {
   }
 }
 
+.profile-viewer__admin-tool {
+  .setting-tile {
+    margin-top: var(--sp-loose);
+  }
+}
+
+.moderation-tools {
+  & > form {
+    margin: var(--sp-normal) 0;
+    display: flex;
+    align-items: flex-end;
+    & .input-container {
+      @extend .cp-fx__item-one;
+      @include dir.side(margin, 0, var(--sp-tight));
+    }
+    & button {
+      height: 46px;
+    }
+  }
+}
+
 .session-info {
   & .setting-tile__title .text {
     color: var(--tc-surface-high);
index 73783ef0c677be2639e1e6ece7ca874c39cda783..8d67afd0325d7db82a98ed7b7ccf353bc5592446 100644 (file)
@@ -192,10 +192,10 @@ async function invite(roomId, userId) {
   return result;
 }
 
-async function kick(roomId, userId) {
+async function kick(roomId, userId, reason) {
   const mx = initMatrix.matrixClient;
 
-  const result = await mx.kick(roomId, userId);
+  const result = await mx.kick(roomId, userId, reason);
   return result;
 }