Add room profile comp

Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
Ajay Bura 2021-12-22 20:17:01 +05:30
parent 23c430fadc
commit 8eda0aeab3
2 changed files with 232 additions and 0 deletions

View file

@ -0,0 +1,179 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import './RoomProfile.scss';
import { twemojify } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons';
import colorMXID from '../../../util/colorMXID';
import Text from '../../atoms/text/Text';
import Avatar from '../../atoms/avatar/Avatar';
import Button from '../../atoms/button/Button';
import Input from '../../atoms/input/Input';
import IconButton from '../../atoms/button/IconButton';
import ImageUpload from '../image-upload/ImageUpload';
import PencilIC from '../../../../public/res/ic/outlined/pencil.svg';
import { useStore } from '../../hooks/useStore';
function RoomProfile({ roomId }) {
const isMountStore = useStore();
const [isEditing, setIsEditing] = useState(false);
const [status, setStatus] = useState({
msg: null,
type: cons.status.PRE_FLIGHT,
});
const mx = initMatrix.matrixClient;
const isDM = initMatrix.roomList.directs.has(roomId);
let avatarSrc = mx.getRoom(roomId).getAvatarUrl(mx.baseUrl, 36, 36, 'crop');
avatarSrc = isDM ? mx.getRoom(roomId).getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 36, 36, 'crop') : avatarSrc;
const room = mx.getRoom(roomId);
const { currentState } = room;
const roomName = room.name;
const roomTopic = currentState.getStateEvents('m.room.topic')[0]?.getContent().topic;
const userId = mx.getUserId();
const canChangeAvatar = currentState.maySendStateEvent('m.room.avatar', userId);
const canChangeName = currentState.maySendStateEvent('m.room.name', userId);
const canChangeTopic = currentState.maySendStateEvent('m.room.topic', userId);
useEffect(() => {
isMountStore.setItem(true);
return () => {
isMountStore.setItem(false);
setStatus({
msg: null,
type: cons.status.PRE_FLIGHT,
});
setIsEditing(false);
};
}, [roomId]);
const handleOnSubmit = async (e) => {
e.preventDefault();
const { target } = e;
const roomNameInput = target.elements['room-name'];
const roomTopicInput = target.elements['room-topic'];
try {
if (canChangeName) {
const newName = roomNameInput.value;
if (newName !== roomName && roomName.trim() !== '') {
setStatus({
msg: 'Saving room name...',
type: cons.status.IN_FLIGHT,
});
await mx.setRoomName(roomId, newName);
}
}
if (canChangeTopic) {
const newTopic = roomTopicInput.value;
if (newTopic !== roomTopic) {
if (isMountStore.getItem()) {
setStatus({
msg: 'Saving room topic...',
type: cons.status.IN_FLIGHT,
});
}
await mx.setRoomTopic(roomId, newTopic);
}
}
if (!isMountStore.getItem()) return;
setStatus({
msg: 'Saved successfully',
type: cons.status.SUCCESS,
});
} catch (err) {
if (!isMountStore.getItem()) return;
setStatus({
msg: err.message || 'Unable to save.',
type: cons.status.ERROR,
});
}
};
const handleCancelEditing = () => {
setStatus({
msg: null,
type: cons.status.PRE_FLIGHT,
});
setIsEditing(false);
};
const handleAvatarUpload = async (url) => {
if (url === null) {
if (confirm('Are you sure you want to remove avatar?')) {
await mx.sendStateEvent(roomId, 'm.room.avatar', { url }, '');
}
} else await mx.sendStateEvent(roomId, 'm.room.avatar', { url }, '');
if (!isMountStore.getItem()) return;
setStatus({
msg: null,
type: cons.status.PRE_FLIGHT,
});
};
const renderEditNameAndTopic = () => (
<form className="room-profile__edit-form" onSubmit={handleOnSubmit}>
{canChangeName && <Input value={roomName} name="room-name" disabled={status.type === cons.status.IN_FLIGHT} label="Room name" required />}
{canChangeTopic && <Input value={roomTopic} name="room-topic" disabled={status.type === cons.status.IN_FLIGHT} minHeight={100} resizable label="Topic" />}
{(!canChangeName || !canChangeTopic) && <Text variant="b3">{`You have permission to change room ${canChangeName ? 'name' : 'topic'} only.`}</Text>}
{ status.type === cons.status.IN_FLIGHT && <Text variant="b2">{status.msg}</Text>}
{ status.type === cons.status.SUCCESS && <Text style={{ color: 'var(--tc-positive-high)' }} variant="b2">{status.msg}</Text>}
{ status.type === cons.status.ERROR && <Text style={{ color: 'var(--tc-danger-high)' }} variant="b2">{status.msg}</Text>}
{ status.type !== cons.status.IN_FLIGHT && (
<div>
<Button type="submit" variant="primary">Save</Button>
<Button onClick={handleCancelEditing}>Cancel</Button>
</div>
)}
</form>
);
const renderNameAndTopic = () => (
<div className="room-profile__display" style={{ marginBottom: avatarSrc && canChangeAvatar ? '24px' : '0' }}>
<div>
<Text variant="h2" weight="medium" primary>{twemojify(roomName)}</Text>
{ (canChangeName || canChangeTopic) && (
<IconButton
src={PencilIC}
size="extra-small"
tooltip="Edit room name and topic"
onClick={() => setIsEditing(true)}
/>
)}
</div>
{roomTopic && <Text variant="b2">{twemojify(roomTopic, undefined, true)}</Text>}
</div>
);
return (
<div className="room-profile">
<div className="room-profile__content">
{ !canChangeAvatar && <Avatar imageSrc={avatarSrc} text={roomName} bgColor={colorMXID(roomId)} size="large" />}
{ canChangeAvatar && (
<ImageUpload
text={roomName}
bgColor={colorMXID(roomId)}
imageSrc={avatarSrc}
onUpload={handleAvatarUpload}
onRequestRemove={() => handleAvatarUpload(null)}
/>
)}
{!isEditing && renderNameAndTopic()}
{isEditing && renderEditNameAndTopic()}
</div>
</div>
);
}
RoomProfile.propTypes = {
roomId: PropTypes.string.isRequired,
};
export default RoomProfile;

View file

@ -0,0 +1,53 @@
@use '../../partials/flex';
@use '../../partials/dir';
.room-profile {
&__content {
@extend .cp-fx__row;
& .avatar-container {
min-width: var(--av-large);
}
}
&__display {
align-self: flex-end;
@include dir.side(margin, var(--sp-loose), 0);
& > div:first-child {
@extend .cp-fx__row--s-c;
& > .text {
@include dir.side(margin, 0, var(--sp-extra-tight));
}
}
& > *:last-child {
margin-top: var(--sp-ultra-tight);
white-space: pre-wrap;
word-break: break-word;
}
}
&__edit-form {
@extend .cp-fx__item-one;
@include dir.side(margin, var(--sp-loose), 0);
& .input-container {
margin-bottom: var(--sp-extra-tight);
}
& > .text {
margin-bottom: var(--sp-tight);
}
& > *:last-child {
@extend .cp-fx__item-one;
@extend .cp-fx__row;
margin-top: var(--sp-tight);
.btn-primary {
@include dir.side(margin, 0, var(--sp-tight));
}
}
}
}