mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 14:30:29 +03:00 
			
		
		
		
	Implement Profile Viewer (#130)
* Implement Profile Viewer Fixes #111 * Make user avatar in chat clickable * design progress * Refactored code * progress * Updated chip comp Signed-off-by: Ajay Bura <ajbura@gmail.com> * Refactored ProfileViewer comp Signed-off-by: Ajay Bura <ajbura@gmail.com> * Added msg functionality in ProfileViewer Signed-off-by: Ajay Bura <ajbura@gmail.com> * Added Ignore functionality in ProfileViewer Signed-off-by: Ajay Bura <ajbura@gmail.com> * Fixed Ignore btn bug Signed-off-by: Ajay Bura <ajbura@gmail.com> * Refectored ProfileViewer comp Signed-off-by: Ajay Bura <ajbura@gmail.com> Co-authored-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
		
							parent
							
								
									8d95fd0ca0
								
							
						
					
					
						commit
						fa10a67811
					
				
					 17 changed files with 425 additions and 32 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,4 +1,6 @@
 | 
				
			||||||
experiment
 | 
					experiment
 | 
				
			||||||
dist
 | 
					dist
 | 
				
			||||||
node_modules
 | 
					node_modules
 | 
				
			||||||
devAssets
 | 
					devAssets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								public/res/ic/outlined/shield-empty.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								public/res/ic/outlined/shield-empty.svg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
				
			||||||
 | 
					<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
				
			||||||
 | 
					<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
				
			||||||
 | 
						 viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
 | 
				
			||||||
 | 
					<path d="M12,2L3,6v7c0,5,4,9,9,9c5,0,9-4,9-9V6L12,2z M19,13c0,3.9-3.1,7-7,7s-7-3.1-7-7V7.3l7-3.1l7,3.1V13z"/>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 554 B  | 
| 
						 | 
					@ -24,7 +24,6 @@
 | 
				
			||||||
    height: var(--av-extra-small);
 | 
					    height: var(--av-extra-small);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  img {
 | 
					  img {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    height: 100%;
 | 
					    height: 100%;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,14 @@ import RawIcon from '../system-icons/RawIcon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Chip({
 | 
					function Chip({
 | 
				
			||||||
  iconSrc, iconColor, text, children,
 | 
					  iconSrc, iconColor, text, children,
 | 
				
			||||||
 | 
					  onClick,
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="chip">
 | 
					    <button className="chip" type="button" onClick={onClick}>
 | 
				
			||||||
      {iconSrc != null && <RawIcon src={iconSrc} color={iconColor} size="small" />}
 | 
					      {iconSrc != null && <RawIcon src={iconSrc} color={iconColor} size="extra-small" />}
 | 
				
			||||||
      {(text != null && text !== '') && <Text variant="b2">{text}</Text>}
 | 
					      {(text != null && text !== '') && <Text variant="b3">{text}</Text>}
 | 
				
			||||||
      {children}
 | 
					      {children}
 | 
				
			||||||
    </div>
 | 
					    </button>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +23,7 @@ Chip.propTypes = {
 | 
				
			||||||
  iconColor: PropTypes.string,
 | 
					  iconColor: PropTypes.string,
 | 
				
			||||||
  text: PropTypes.string,
 | 
					  text: PropTypes.string,
 | 
				
			||||||
  children: PropTypes.element,
 | 
					  children: PropTypes.element,
 | 
				
			||||||
 | 
					  onClick: PropTypes.func,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Chip.defaultProps = {
 | 
					Chip.defaultProps = {
 | 
				
			||||||
| 
						 | 
					@ -29,6 +31,7 @@ Chip.defaultProps = {
 | 
				
			||||||
  iconColor: null,
 | 
					  iconColor: null,
 | 
				
			||||||
  text: null,
 | 
					  text: null,
 | 
				
			||||||
  children: null,
 | 
					  children: null,
 | 
				
			||||||
 | 
					  onClick: null,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Chip;
 | 
					export default Chip;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,27 @@
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  background: var(--bg-surface-low);
 | 
					  background: var(--bg-surface-low);
 | 
				
			||||||
  border-radius: var(--bo-radius);
 | 
					  border-radius: var(--bo-radius);
 | 
				
			||||||
  border: 1px solid var(--bg-surface-border);
 | 
					  box-shadow: var(--bs-surface-border);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @media (hover: hover) {
 | 
				
			||||||
 | 
					    &:hover {
 | 
				
			||||||
 | 
					      background-color: var(--bg-surface-hover);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  & > .text {
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					    color: var(--tc-surface-high);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  & > .ic-raw {
 | 
					  & > .ic-raw {
 | 
				
			||||||
    margin-right: var(--sp-extra-tight);
 | 
					    width: 16px;
 | 
				
			||||||
 | 
					    height: 16px;
 | 
				
			||||||
 | 
					    margin-right: var(--sp-ultra-tight);
 | 
				
			||||||
    [dir=rtl] & {
 | 
					    [dir=rtl] & {
 | 
				
			||||||
      margin-right: 0;
 | 
					      margin-right: 0;
 | 
				
			||||||
      margin-left: var(--sp-extra-tight);
 | 
					      margin-left: var(--sp-ultra-tight);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -22,11 +22,12 @@
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  &__avatar-container {
 | 
					  &__avatar-container {
 | 
				
			||||||
    padding-top: 6px;
 | 
					    padding-top: 6px;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  &__avatar-container{
 | 
					 | 
				
			||||||
    margin-right: var(--sp-tight);
 | 
					    margin-right: var(--sp-tight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & button {
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [dir=rtl] & {
 | 
					    [dir=rtl] & {
 | 
				
			||||||
      margin: {
 | 
					      margin: {
 | 
				
			||||||
        left: var(--sp-tight);
 | 
					        left: var(--sp-tight);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ function RoomIntro({
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RoomIntro.defaultProps = {
 | 
					RoomIntro.defaultProps = {
 | 
				
			||||||
  avatarSrc: false,
 | 
					  avatarSrc: null,
 | 
				
			||||||
  time: null,
 | 
					  time: null,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										255
									
								
								src/app/organisms/profile-viewer/ProfileViewer.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								src/app/organisms/profile-viewer/ProfileViewer.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,255 @@
 | 
				
			||||||
 | 
					import React, { useState, useEffect, useRef } from 'react';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					import './ProfileViewer.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import initMatrix from '../../../client/initMatrix';
 | 
				
			||||||
 | 
					import cons from '../../../client/state/cons';
 | 
				
			||||||
 | 
					import navigation from '../../../client/state/navigation';
 | 
				
			||||||
 | 
					import { selectRoom } from '../../../client/action/navigation';
 | 
				
			||||||
 | 
					import * as roomActions from '../../../client/action/room';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { getUsername, getUsernameOfRoomMember, getPowerLabel } from '../../../util/matrixUtil';
 | 
				
			||||||
 | 
					import colorMXID from '../../../util/colorMXID';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Text from '../../atoms/text/Text';
 | 
				
			||||||
 | 
					import Chip from '../../atoms/chip/Chip';
 | 
				
			||||||
 | 
					import IconButton from '../../atoms/button/IconButton';
 | 
				
			||||||
 | 
					import Avatar from '../../atoms/avatar/Avatar';
 | 
				
			||||||
 | 
					import Button from '../../atoms/button/Button';
 | 
				
			||||||
 | 
					import Dialog from '../../molecules/dialog/Dialog';
 | 
				
			||||||
 | 
					import SettingTile from '../../molecules/setting-tile/SettingTile';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import ShieldEmptyIC from '../../../../public/res/ic/outlined/shield-empty.svg';
 | 
				
			||||||
 | 
					import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
 | 
				
			||||||
 | 
					import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function SessionInfo({ userId }) {
 | 
				
			||||||
 | 
					  const [devices, setDevices] = useState(null);
 | 
				
			||||||
 | 
					  const mx = initMatrix.matrixClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    let isUnmounted = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async function loadDevices() {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        await mx.downloadKeys([userId], true);
 | 
				
			||||||
 | 
					        const myDevices = mx.getStoredDevicesForUser(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isUnmounted) return;
 | 
				
			||||||
 | 
					        setDevices(myDevices);
 | 
				
			||||||
 | 
					      } catch {
 | 
				
			||||||
 | 
					        setDevices([]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    loadDevices();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      isUnmounted = true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, [userId]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function renderSessionChips() {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div className="session-info__chips">
 | 
				
			||||||
 | 
					        {devices === null && <Text variant="b3">Loading sessions...</Text>}
 | 
				
			||||||
 | 
					        {devices?.length === 0 && <Text variant="b3">No session found.</Text>}
 | 
				
			||||||
 | 
					        {devices !== null && (devices.map((device) => (
 | 
				
			||||||
 | 
					          <Chip
 | 
				
			||||||
 | 
					            key={device.deviceId}
 | 
				
			||||||
 | 
					            iconSrc={ShieldEmptyIC}
 | 
				
			||||||
 | 
					            text={device.getDisplayName() || device.deviceId}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )))}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="session-info">
 | 
				
			||||||
 | 
					      <SettingTile
 | 
				
			||||||
 | 
					        title="Sessions"
 | 
				
			||||||
 | 
					        content={renderSessionChips()}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SessionInfo.propTypes = {
 | 
				
			||||||
 | 
					  userId: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ProfileFooter({ userId, onRequestClose }) {
 | 
				
			||||||
 | 
					  const [isCreatingDM, setIsCreatingDM] = useState(false);
 | 
				
			||||||
 | 
					  const [isIgnoring, setIsIgnoring] = useState(false);
 | 
				
			||||||
 | 
					  const [isUserIgnored, setIsUserIgnored] = useState(initMatrix.matrixClient.isUserIgnored(userId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const mx = initMatrix.matrixClient;
 | 
				
			||||||
 | 
					  const isMountedRef = useRef(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => () => {
 | 
				
			||||||
 | 
					    isMountedRef.current = false;
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    setIsUserIgnored(initMatrix.matrixClient.isUserIgnored(userId));
 | 
				
			||||||
 | 
					  }, [userId]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function openDM() {
 | 
				
			||||||
 | 
					    const directIds = [...initMatrix.roomList.directs];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check and open if user already have a DM with userId.
 | 
				
			||||||
 | 
					    for (let i = 0; i < directIds.length; i += 1) {
 | 
				
			||||||
 | 
					      const dRoom = mx.getRoom(directIds[i]);
 | 
				
			||||||
 | 
					      const roomMembers = dRoom.getMembers();
 | 
				
			||||||
 | 
					      if (roomMembers.length <= 2 && dRoom.currentState.members[userId]) {
 | 
				
			||||||
 | 
					        selectRoom(directIds[i]);
 | 
				
			||||||
 | 
					        onRequestClose();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create new DM
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      setIsCreatingDM(true);
 | 
				
			||||||
 | 
					      const result = await roomActions.create({
 | 
				
			||||||
 | 
					        isEncrypted: true,
 | 
				
			||||||
 | 
					        isDirect: true,
 | 
				
			||||||
 | 
					        invite: [userId],
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isMountedRef.current === false) return;
 | 
				
			||||||
 | 
					      setIsCreatingDM(false);
 | 
				
			||||||
 | 
					      selectRoom(result.room_id);
 | 
				
			||||||
 | 
					      onRequestClose();
 | 
				
			||||||
 | 
					    } catch {
 | 
				
			||||||
 | 
					      setIsCreatingDM(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function toggleIgnore() {
 | 
				
			||||||
 | 
					    const ignoredUsers = mx.getIgnoredUsers();
 | 
				
			||||||
 | 
					    const uIndex = ignoredUsers.indexOf(userId);
 | 
				
			||||||
 | 
					    if (uIndex >= 0) {
 | 
				
			||||||
 | 
					      if (uIndex === -1) return;
 | 
				
			||||||
 | 
					      ignoredUsers.splice(uIndex, 1);
 | 
				
			||||||
 | 
					    } else ignoredUsers.push(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      setIsIgnoring(true);
 | 
				
			||||||
 | 
					      await mx.setIgnoredUsers(ignoredUsers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isMountedRef.current === false) return;
 | 
				
			||||||
 | 
					      setIsUserIgnored(uIndex < 0);
 | 
				
			||||||
 | 
					      setIsIgnoring(false);
 | 
				
			||||||
 | 
					    } catch {
 | 
				
			||||||
 | 
					      setIsIgnoring(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="profile-viewer__buttons">
 | 
				
			||||||
 | 
					      <Button
 | 
				
			||||||
 | 
					        variant="primary"
 | 
				
			||||||
 | 
					        onClick={openDM}
 | 
				
			||||||
 | 
					        disabled={isCreatingDM}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {isCreatingDM ? 'Creating room...' : 'Message'}
 | 
				
			||||||
 | 
					      </Button>
 | 
				
			||||||
 | 
					      <Button>Mention</Button>
 | 
				
			||||||
 | 
					      <Button
 | 
				
			||||||
 | 
					        variant={isUserIgnored ? 'positive' : 'danger'}
 | 
				
			||||||
 | 
					        onClick={toggleIgnore}
 | 
				
			||||||
 | 
					        disabled={isIgnoring}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          isUserIgnored
 | 
				
			||||||
 | 
					            ? `${isIgnoring ? 'Unignoring...' : 'Unignore'}`
 | 
				
			||||||
 | 
					            : `${isIgnoring ? 'Ignoring...' : 'Ignore'}`
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      </Button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					ProfileFooter.propTypes = {
 | 
				
			||||||
 | 
					  userId: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					  onRequestClose: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ProfileViewer() {
 | 
				
			||||||
 | 
					  const [isOpen, setIsOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [roomId, setRoomId] = useState(null);
 | 
				
			||||||
 | 
					  const [userId, setUserId] = useState(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const mx = initMatrix.matrixClient;
 | 
				
			||||||
 | 
					  const room = roomId ? mx.getRoom(roomId) : null;
 | 
				
			||||||
 | 
					  let username = '';
 | 
				
			||||||
 | 
					  if (room !== null) {
 | 
				
			||||||
 | 
					    const roomMember = room.getMember(userId);
 | 
				
			||||||
 | 
					    if (roomMember) username = getUsernameOfRoomMember(roomMember);
 | 
				
			||||||
 | 
					    else username = getUsername(userId);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function loadProfile(uId, rId) {
 | 
				
			||||||
 | 
					    setIsOpen(true);
 | 
				
			||||||
 | 
					    setUserId(uId);
 | 
				
			||||||
 | 
					    setRoomId(rId);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    navigation.on(cons.events.navigation.PROFILE_VIEWER_OPENED, loadProfile);
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      navigation.removeListener(cons.events.navigation.PROFILE_VIEWER_OPENED, loadProfile);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (isOpen) return;
 | 
				
			||||||
 | 
					    setUserId(null);
 | 
				
			||||||
 | 
					    setRoomId(null);
 | 
				
			||||||
 | 
					  }, [isOpen]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function renderProfile() {
 | 
				
			||||||
 | 
					    const member = room.getMember(userId) || mx.getUser(userId);
 | 
				
			||||||
 | 
					    const avatarMxc = member.getMxcAvatarUrl() || member.avatarUrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div className="profile-viewer">
 | 
				
			||||||
 | 
					        <div className="profile-viewer__user">
 | 
				
			||||||
 | 
					          <Avatar
 | 
				
			||||||
 | 
					            imageSrc={!avatarMxc ? null : mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop')}
 | 
				
			||||||
 | 
					            text={username.slice(0, 1)}
 | 
				
			||||||
 | 
					            bgColor={colorMXID(userId)}
 | 
				
			||||||
 | 
					            size="large"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <div className="profile-viewer__user__info">
 | 
				
			||||||
 | 
					            <Text variant="s1">{username}</Text>
 | 
				
			||||||
 | 
					            <Text variant="b2">{userId}</Text>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="profile-viewer__user__role">
 | 
				
			||||||
 | 
					            <Text variant="b3">Role</Text>
 | 
				
			||||||
 | 
					            <Button iconSrc={ChevronBottomIC}>{getPowerLabel(member.powerLevel) || 'Member'}</Button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <SessionInfo userId={userId} />
 | 
				
			||||||
 | 
					        { userId !== mx.getUserId() && (
 | 
				
			||||||
 | 
					          <ProfileFooter
 | 
				
			||||||
 | 
					            userId={userId}
 | 
				
			||||||
 | 
					            onRequestClose={() => setIsOpen(false)}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Dialog
 | 
				
			||||||
 | 
					      className="profile-viewer__dialog"
 | 
				
			||||||
 | 
					      isOpen={isOpen}
 | 
				
			||||||
 | 
					      title={`${username} in ${room?.name ?? ''}`}
 | 
				
			||||||
 | 
					      onRequestClose={() => setIsOpen(false)}
 | 
				
			||||||
 | 
					      contentOptions={<IconButton src={CrossIC} onClick={() => setIsOpen(false)} tooltip="Close" />}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {isOpen && renderProfile()}
 | 
				
			||||||
 | 
					    </Dialog>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ProfileViewer;
 | 
				
			||||||
							
								
								
									
										89
									
								
								src/app/organisms/profile-viewer/ProfileViewer.scss
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/app/organisms/profile-viewer/ProfileViewer.scss
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					.profile-viewer__dialog {
 | 
				
			||||||
 | 
					  & .dialog__content__wrapper {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  & .dialog__content-container {
 | 
				
			||||||
 | 
					    padding: var(--sp-normal);
 | 
				
			||||||
 | 
					    padding-bottom: 89px;
 | 
				
			||||||
 | 
					    padding-right: var(--sp-extra-tight);
 | 
				
			||||||
 | 
					    [dir=rtl] & {
 | 
				
			||||||
 | 
					      padding-right: var(--sp-normal);
 | 
				
			||||||
 | 
					      padding-left: var(--sp-extra-tight);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-viewer {
 | 
				
			||||||
 | 
					  &__user {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    padding-bottom: var(--sp-normal);
 | 
				
			||||||
 | 
					    border-bottom: 1px solid var(--bg-surface-border);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &__info {
 | 
				
			||||||
 | 
					      align-self: end;
 | 
				
			||||||
 | 
					      flex: 1;
 | 
				
			||||||
 | 
					      min-width: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      margin: 0 var(--sp-normal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      & .text-s1 {
 | 
				
			||||||
 | 
					        font-weight: 500;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      & .text {
 | 
				
			||||||
 | 
					        white-space: pre-wrap;
 | 
				
			||||||
 | 
					        word-break: break-word;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    &__role {
 | 
				
			||||||
 | 
					      align-self: end;
 | 
				
			||||||
 | 
					      & > .text {
 | 
				
			||||||
 | 
					        margin-bottom: var(--sp-ultra-tight);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  & .session-info {
 | 
				
			||||||
 | 
					    margin-top: var(--sp-normal);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &__buttons {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    padding: var(--sp-normal);
 | 
				
			||||||
 | 
					    background-color: var(--bg-surface);
 | 
				
			||||||
 | 
					    border-top: 1px solid var(--bg-surface-border);
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > *:nth-child(2n) {
 | 
				
			||||||
 | 
					      margin: 0 var(--sp-normal)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    & > *:last-child {
 | 
				
			||||||
 | 
					      margin-left: auto;
 | 
				
			||||||
 | 
					      [dir=rtl] & {
 | 
				
			||||||
 | 
					        margin-left: 0;
 | 
				
			||||||
 | 
					        margin-right: auto;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.session-info {
 | 
				
			||||||
 | 
					  & .setting-tile__title .text {
 | 
				
			||||||
 | 
					    color: var(--tc-surface-high);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &__chips {
 | 
				
			||||||
 | 
					    padding-top: var(--sp-ultra-tight);
 | 
				
			||||||
 | 
					    & .chip {
 | 
				
			||||||
 | 
					      margin: {
 | 
				
			||||||
 | 
					        top: var(--sp-extra-tight);
 | 
				
			||||||
 | 
					        right: var(--sp-extra-tight);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      [dir=rtl] & {
 | 
				
			||||||
 | 
					        margin: 0 0 var(--sp-extra-tight) var(--sp-extra-tight);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } 
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,13 @@
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ReadReceipts from '../read-receipts/ReadReceipts';
 | 
					import ReadReceipts from '../read-receipts/ReadReceipts';
 | 
				
			||||||
 | 
					import ProfileViewer from '../profile-viewer/ProfileViewer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Dialogs() {
 | 
					function Dialogs() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <ReadReceipts />
 | 
					      <ReadReceipts />
 | 
				
			||||||
 | 
					      <ProfileViewer />
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ import PeopleSelector from '../../molecules/people-selector/PeopleSelector';
 | 
				
			||||||
import Dialog from '../../molecules/dialog/Dialog';
 | 
					import Dialog from '../../molecules/dialog/Dialog';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
					import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 | 
				
			||||||
 | 
					import { openProfileViewer } from '../../../client/action/navigation';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function ReadReceipts() {
 | 
					function ReadReceipts() {
 | 
				
			||||||
  const [isOpen, setIsOpen] = useState(false);
 | 
					  const [isOpen, setIsOpen] = useState(false);
 | 
				
			||||||
| 
						 | 
					@ -58,7 +59,10 @@ function ReadReceipts() {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <PeopleSelector
 | 
					      <PeopleSelector
 | 
				
			||||||
        key={receipt.userId}
 | 
					        key={receipt.userId}
 | 
				
			||||||
        onClick={() => alert('Viewing profile is yet to be implemented')}
 | 
					        onClick={() => {
 | 
				
			||||||
 | 
					          setIsOpen(false);
 | 
				
			||||||
 | 
					          openProfileViewer(receipt.userId, roomId);
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
        avatarSrc={member?.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
 | 
					        avatarSrc={member?.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
 | 
				
			||||||
        name={getUserDisplayName(receipt.userId)}
 | 
					        name={getUserDisplayName(receipt.userId)}
 | 
				
			||||||
        color={colorMXID(receipt.userId)}
 | 
					        color={colorMXID(receipt.userId)}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,9 +3,9 @@ import PropTypes from 'prop-types';
 | 
				
			||||||
import './PeopleDrawer.scss';
 | 
					import './PeopleDrawer.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import initMatrix from '../../../client/initMatrix';
 | 
					import initMatrix from '../../../client/initMatrix';
 | 
				
			||||||
import { getUsernameOfRoomMember } from '../../../util/matrixUtil';
 | 
					import { getPowerLabel, getUsernameOfRoomMember } from '../../../util/matrixUtil';
 | 
				
			||||||
import colorMXID from '../../../util/colorMXID';
 | 
					import colorMXID from '../../../util/colorMXID';
 | 
				
			||||||
import { openInviteUser } from '../../../client/action/navigation';
 | 
					import { openInviteUser, openProfileViewer } from '../../../client/action/navigation';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Text from '../../atoms/text/Text';
 | 
					import Text from '../../atoms/text/Text';
 | 
				
			||||||
import Header, { TitleWrapper } from '../../atoms/header/Header';
 | 
					import Header, { TitleWrapper } from '../../atoms/header/Header';
 | 
				
			||||||
| 
						 | 
					@ -17,13 +17,6 @@ import PeopleSelector from '../../molecules/people-selector/PeopleSelector';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
 | 
					import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getPowerLabel(powerLevel) {
 | 
					 | 
				
			||||||
  if (powerLevel > 9000) return 'Goku';
 | 
					 | 
				
			||||||
  if (powerLevel > 100) return 'Founder';
 | 
					 | 
				
			||||||
  if (powerLevel === 100) return 'Admin';
 | 
					 | 
				
			||||||
  if (powerLevel >= 50) return 'Mod';
 | 
					 | 
				
			||||||
  return null;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
function AtoZ(m1, m2) {
 | 
					function AtoZ(m1, m2) {
 | 
				
			||||||
  const aName = m1.name;
 | 
					  const aName = m1.name;
 | 
				
			||||||
  const bName = m2.name;
 | 
					  const bName = m2.name;
 | 
				
			||||||
| 
						 | 
					@ -88,7 +81,7 @@ function PeopleDrawer({ roomId }) {
 | 
				
			||||||
                memberList.map((member) => (
 | 
					                memberList.map((member) => (
 | 
				
			||||||
                  <PeopleSelector
 | 
					                  <PeopleSelector
 | 
				
			||||||
                    key={member.userId}
 | 
					                    key={member.userId}
 | 
				
			||||||
                    onClick={() => alert('Viewing profile is yet to be implemented')}
 | 
					                    onClick={() => openProfileViewer(member.userId, roomId)}
 | 
				
			||||||
                    avatarSrc={member.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
 | 
					                    avatarSrc={member.getAvatarUrl(initMatrix.matrixClient.baseUrl, 24, 24, 'crop')}
 | 
				
			||||||
                    name={getUsernameOfRoomMember(member)}
 | 
					                    name={getUsernameOfRoomMember(member)}
 | 
				
			||||||
                    color={colorMXID(member.userId)}
 | 
					                    color={colorMXID(member.userId)}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ import { redactEvent, sendReaction } from '../../../client/action/roomTimeline';
 | 
				
			||||||
import { getUsername, getUsernameOfRoomMember, doesRoomHaveUnread } from '../../../util/matrixUtil';
 | 
					import { getUsername, getUsernameOfRoomMember, doesRoomHaveUnread } from '../../../util/matrixUtil';
 | 
				
			||||||
import colorMXID from '../../../util/colorMXID';
 | 
					import colorMXID from '../../../util/colorMXID';
 | 
				
			||||||
import { diffMinutes, isNotInSameDay, getEventCords } from '../../../util/common';
 | 
					import { diffMinutes, isNotInSameDay, getEventCords } from '../../../util/common';
 | 
				
			||||||
import { openEmojiBoard, openReadReceipts } from '../../../client/action/navigation';
 | 
					import { openEmojiBoard, openProfileViewer, openReadReceipts } from '../../../client/action/navigation';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Divider from '../../atoms/divider/Divider';
 | 
					import Divider from '../../atoms/divider/Divider';
 | 
				
			||||||
import Avatar from '../../atoms/avatar/Avatar';
 | 
					import Avatar from '../../atoms/avatar/Avatar';
 | 
				
			||||||
| 
						 | 
					@ -353,12 +353,14 @@ function RoomViewContent({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const senderMXIDColor = colorMXID(mEvent.sender.userId);
 | 
					    const senderMXIDColor = colorMXID(mEvent.sender.userId);
 | 
				
			||||||
    const userAvatar = isContentOnly ? null : (
 | 
					    const userAvatar = isContentOnly ? null : (
 | 
				
			||||||
      <Avatar
 | 
					      <button type="button" onClick={() => openProfileViewer(mEvent.sender.userId, roomId)}>
 | 
				
			||||||
        imageSrc={mEvent.sender.getAvatarUrl(initMatrix.matrixClient.baseUrl, 36, 36, 'crop')}
 | 
					        <Avatar
 | 
				
			||||||
        text={getUsernameOfRoomMember(mEvent.sender).slice(0, 1)}
 | 
					          imageSrc={mEvent.sender.getAvatarUrl(initMatrix.matrixClient.baseUrl, 36, 36, 'crop')}
 | 
				
			||||||
        bgColor={senderMXIDColor}
 | 
					          text={getUsernameOfRoomMember(mEvent.sender).slice(0, 1)}
 | 
				
			||||||
        size="small"
 | 
					          bgColor={senderMXIDColor}
 | 
				
			||||||
      />
 | 
					          size="small"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    const userHeader = isContentOnly ? null : (
 | 
					    const userHeader = isContentOnly ? null : (
 | 
				
			||||||
      <MessageHeader
 | 
					      <MessageHeader
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,14 @@ function openInviteUser(roomId, searchTerm) {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function openProfileViewer(userId, roomId) {
 | 
				
			||||||
 | 
					  appDispatcher.dispatch({
 | 
				
			||||||
 | 
					    type: cons.actions.navigation.OPEN_PROFILE_VIEWER,
 | 
				
			||||||
 | 
					    userId,
 | 
				
			||||||
 | 
					    roomId,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function openSettings() {
 | 
					function openSettings() {
 | 
				
			||||||
  appDispatcher.dispatch({
 | 
					  appDispatcher.dispatch({
 | 
				
			||||||
    type: cons.actions.navigation.OPEN_SETTINGS,
 | 
					    type: cons.actions.navigation.OPEN_SETTINGS,
 | 
				
			||||||
| 
						 | 
					@ -94,6 +102,7 @@ export {
 | 
				
			||||||
  openPublicRooms,
 | 
					  openPublicRooms,
 | 
				
			||||||
  openCreateRoom,
 | 
					  openCreateRoom,
 | 
				
			||||||
  openInviteUser,
 | 
					  openInviteUser,
 | 
				
			||||||
 | 
					  openProfileViewer,
 | 
				
			||||||
  openSettings,
 | 
					  openSettings,
 | 
				
			||||||
  openEmojiBoard,
 | 
					  openEmojiBoard,
 | 
				
			||||||
  openReadReceipts,
 | 
					  openReadReceipts,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ const cons = {
 | 
				
			||||||
      OPEN_PUBLIC_ROOMS: 'OPEN_PUBLIC_ROOMS',
 | 
					      OPEN_PUBLIC_ROOMS: 'OPEN_PUBLIC_ROOMS',
 | 
				
			||||||
      OPEN_CREATE_ROOM: 'OPEN_CREATE_ROOM',
 | 
					      OPEN_CREATE_ROOM: 'OPEN_CREATE_ROOM',
 | 
				
			||||||
      OPEN_INVITE_USER: 'OPEN_INVITE_USER',
 | 
					      OPEN_INVITE_USER: 'OPEN_INVITE_USER',
 | 
				
			||||||
 | 
					      OPEN_PROFILE_VIEWER: 'OPEN_PROFILE_VIEWER',
 | 
				
			||||||
      OPEN_SETTINGS: 'OPEN_SETTINGS',
 | 
					      OPEN_SETTINGS: 'OPEN_SETTINGS',
 | 
				
			||||||
      OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD',
 | 
					      OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD',
 | 
				
			||||||
      OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
 | 
					      OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
 | 
				
			||||||
| 
						 | 
					@ -57,6 +58,7 @@ const cons = {
 | 
				
			||||||
      CREATE_ROOM_OPENED: 'CREATE_ROOM_OPENED',
 | 
					      CREATE_ROOM_OPENED: 'CREATE_ROOM_OPENED',
 | 
				
			||||||
      INVITE_USER_OPENED: 'INVITE_USER_OPENED',
 | 
					      INVITE_USER_OPENED: 'INVITE_USER_OPENED',
 | 
				
			||||||
      SETTINGS_OPENED: 'SETTINGS_OPENED',
 | 
					      SETTINGS_OPENED: 'SETTINGS_OPENED',
 | 
				
			||||||
 | 
					      PROFILE_VIEWER_OPENED: 'PROFILE_VIEWER_OPENED',
 | 
				
			||||||
      EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED',
 | 
					      EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED',
 | 
				
			||||||
      READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
 | 
					      READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
 | 
				
			||||||
      ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
 | 
					      ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,6 +69,9 @@ class Navigation extends EventEmitter {
 | 
				
			||||||
      [cons.actions.navigation.OPEN_INVITE_USER]: () => {
 | 
					      [cons.actions.navigation.OPEN_INVITE_USER]: () => {
 | 
				
			||||||
        this.emit(cons.events.navigation.INVITE_USER_OPENED, action.roomId, action.searchTerm);
 | 
					        this.emit(cons.events.navigation.INVITE_USER_OPENED, action.roomId, action.searchTerm);
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      [cons.actions.navigation.OPEN_PROFILE_VIEWER]: () => {
 | 
				
			||||||
 | 
					        this.emit(cons.events.navigation.PROFILE_VIEWER_OPENED, action.userId, action.roomId);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      [cons.actions.navigation.OPEN_SETTINGS]: () => {
 | 
					      [cons.actions.navigation.OPEN_SETTINGS]: () => {
 | 
				
			||||||
        this.emit(cons.events.navigation.SETTINGS_OPENED);
 | 
					        this.emit(cons.events.navigation.SETTINGS_OPENED);
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,15 @@ function doesRoomHaveUnread(room) {
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getPowerLabel(powerLevel) {
 | 
				
			||||||
 | 
					  if (powerLevel > 9000) return 'Goku';
 | 
				
			||||||
 | 
					  if (powerLevel > 100) return 'Founder';
 | 
				
			||||||
 | 
					  if (powerLevel === 100) return 'Admin';
 | 
				
			||||||
 | 
					  if (powerLevel >= 50) return 'Mod';
 | 
				
			||||||
 | 
					  return null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
  getBaseUrl, getUsername, getUsernameOfRoomMember,
 | 
					  getBaseUrl, getUsername, getUsernameOfRoomMember,
 | 
				
			||||||
  isRoomAliasAvailable, doesRoomHaveUnread,
 | 
					  isRoomAliasAvailable, doesRoomHaveUnread, getPowerLabel,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue