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
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@ 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…
Reference in a new issue