diff --git a/app/e2e/client/tabbar.ts b/app/e2e/client/tabbar.ts
index e3d23015dd3ea..5b4397d852f23 100644
--- a/app/e2e/client/tabbar.ts
+++ b/app/e2e/client/tabbar.ts
@@ -10,7 +10,7 @@ import { e2e } from './rocketchat.e2e';
addAction('e2e', ({ room }) => {
const e2eEnabled = useSetting('E2E_Enable');
const e2eReady = e2e.isReady() || room.encrypted;
- const e2ePermission = room.t === 'd' || usePermission('toggle-room-e2e-encryption', room._id);
+ const e2ePermission = usePermission('toggle-room-e2e-encryption', room._id) || room.t === 'd';
const hasPermission = usePermission('edit-room', room._id) && e2ePermission && e2eReady;
const toggleE2E = useMethod('saveRoomSettings');
diff --git a/app/ui-message/client/message.js b/app/ui-message/client/message.js
index 3b71f96fd9614..d5f4ed0a2ac40 100644
--- a/app/ui-message/client/message.js
+++ b/app/ui-message/client/message.js
@@ -551,6 +551,11 @@ const processSequentials = ({ index, currentNode, settings, forceDate, showDateS
const previousNode = (index === undefined || index > 0) && getPreviousSentMessage(currentNode);
const nextNode = currentNode.nextElementSibling;
+ if (!previousNode) {
+ setTimeout(() => {
+ currentNode.dispatchEvent(new CustomEvent('MessageGroup', { bubbles: true }));
+ }, 100);
+ }
if (isSequential(currentNode, previousNode, forceDate, settings.Message_GroupingPeriod, showDateSeparator, shouldCollapseReplies)) {
currentNode.classList.add('sequential');
} else {
diff --git a/app/ui-utils/client/lib/RoomManager.js b/app/ui-utils/client/lib/RoomManager.js
index b5506be1b4c0f..ed01f1766fd5c 100644
--- a/app/ui-utils/client/lib/RoomManager.js
+++ b/app/ui-utils/client/lib/RoomManager.js
@@ -4,7 +4,6 @@ import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';
import { Blaze } from 'meteor/blaze';
import { FlowRouter } from 'meteor/kadira:flow-router';
-import { Template } from 'meteor/templating';
import _ from 'underscore';
import { fireGlobalEvent } from './fireGlobalEvent';
@@ -19,7 +18,7 @@ import { CachedCollectionManager } from '../../../ui-cached-collection';
import { getConfig } from '../config';
import { ROOM_DATA_STREAM } from '../../../utils/stream/constants';
import { call } from '..';
-
+import { RoomManager as NewRoomManager } from '../../../../client/lib/RoomManager';
const maxRoomsOpen = parseInt(getConfig('maxRoomsOpen')) || 5;
@@ -143,23 +142,6 @@ export const RoomManager = new function() {
return Object.keys(openedRooms).map((typeName) => openedRooms[typeName]).find((openedRoom) => openedRoom.rid === rid);
}
- getDomOfRoom(typeName, rid, templateName) {
- const room = openedRooms[typeName];
- if (room == null) {
- return;
- }
-
- if ((room.dom == null) && (rid != null)) {
- room.dom = document.createElement('div');
- room.dom.classList.add('room-container');
- const contentAsFunc = (content) => () => content;
-
- room.template = Blaze._TemplateWith({ _id: rid }, contentAsFunc(Template[templateName || 'room']));
- Blaze.render(room.template, room.dom); // , nextNode, parentView
- }
-
- return room.dom;
- }
close(typeName) {
if (openedRooms[typeName]) {
@@ -185,6 +167,7 @@ export const RoomManager = new function() {
delete openedRooms[typeName];
if (rid != null) {
+ NewRoomManager.close(rid);
return RoomHistoryManager.clear(rid);
}
}
@@ -265,34 +248,29 @@ export const RoomManager = new function() {
return onlineUsers.set(onlineUsersValue);
}
- updateMentionsMarksOfRoom(typeName) {
- const dom = this.getDomOfRoom(typeName);
- if (!dom) {
- return;
- }
-
- const [ticksBar] = dom.getElementsByClassName('ticks-bar');
- const [messagesBox] = dom.getElementsByClassName('messages-box');
- const scrollTop = $('> .wrapper', messagesBox).scrollTop() - 50;
- const totalHeight = $(' > .wrapper > ul', messagesBox).height() + 40;
- if (!ticksBar) {
- return;
- }
-
- // TODO: thread quotes should NOT have mention links at all
- const mentionsSelector = '.message .body .mention-link--me, .message .body .mention-link--group';
- ticksBar.innerHTML = Array.from(messagesBox?.querySelectorAll(mentionsSelector) || [])
- .map((mentionLink) => {
- const topOffset = $(mentionLink).offset().top + scrollTop;
- const percent = (100 / totalHeight) * topOffset;
- const className = [
- 'tick',
- mentionLink.classList.contains('mention-link--me') && 'tick--me',
- mentionLink.classList.contains('mention-link--group') && 'tick--group',
- ].filter(Boolean).join(' ');
- return `
`;
- })
- .join('');
+ updateMentionsMarksOfRoom(/* typeName */) {
+ // const [ticksBar] = dom.getElementsByClassName('ticks-bar');
+ // const [messagesBox] = dom.getElementsByClassName('messages-box');
+ // const scrollTop = $('> .wrapper', messagesBox).scrollTop() - 50;
+ // const totalHeight = $(' > .wrapper > ul', messagesBox).height() + 40;
+ // if (!ticksBar) {
+ // return;
+ // }
+
+ // // TODO: thread quotes should NOT have mention links at all
+ // const mentionsSelector = '.message .body .mention-link--me, .message .body .mention-link--group';
+ // ticksBar.innerHTML = Array.from(messagesBox?.querySelectorAll(mentionsSelector) || [])
+ // .map((mentionLink) => {
+ // const topOffset = $(mentionLink).offset().top + scrollTop;
+ // const percent = (100 / totalHeight) * topOffset;
+ // const className = [
+ // 'tick',
+ // mentionLink.classList.contains('mention-link--me') && 'tick--me',
+ // mentionLink.classList.contains('mention-link--group') && 'tick--group',
+ // ].filter(Boolean).join(' ');
+ // return ``;
+ // })
+ // .join('');
}
};
Cls.initClass();
diff --git a/app/ui-utils/client/lib/messageContext.js b/app/ui-utils/client/lib/messageContext.js
index 62342c8d93b66..168b415e3ce91 100644
--- a/app/ui-utils/client/lib/messageContext.js
+++ b/app/ui-utils/client/lib/messageContext.js
@@ -31,6 +31,8 @@ export function messageContext({ rid } = Template.instance()) {
}, {
jump: tmid && tmid !== mid && mid && mid,
});
+ e.preventDefault();
+ e.stopPropagation();
};
const runAction = Layout.isEmbedded() ? (msg, e) => {
@@ -51,6 +53,7 @@ export function messageContext({ rid } = Template.instance()) {
const openDiscussion = (e) => {
e.preventDefault();
+ e.stopPropagation();
const { drid } = e.currentTarget.dataset;
goToRoomById(drid);
};
diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js
index 29b80c19fdbb9..eec44400bc5c1 100644
--- a/app/ui-utils/client/lib/openRoom.js
+++ b/app/ui-utils/client/lib/openRoom.js
@@ -3,35 +3,22 @@ import { Tracker } from 'meteor/tracker';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { Session } from 'meteor/session';
import _ from 'underscore';
-import { Random } from 'meteor/random';
import { appLayout } from '../../../../client/lib/appLayout';
-import { Messages, ChatSubscription, Rooms } from '../../../models';
+import { Messages, ChatSubscription } from '../../../models';
import { settings } from '../../../settings';
import { callbacks } from '../../../callbacks';
import { roomTypes } from '../../../utils';
import { call, callMethod } from './callMethod';
import { RoomManager, fireGlobalEvent, RoomHistoryManager } from '..';
-import { waitUntilWrapperExists } from './RoomHistoryManager';
-import { createTemplateForComponent } from '../../../../client/lib/portals/createTemplateForComponent';
+import { RoomManager as NewRoomManager } from '../../../../client/lib/RoomManager';
+import { Rooms } from '../../../models/client';
window.currentTracker = undefined;
// cleanup session when hot reloading
Session.set('openedRoom', null);
-const replaceCenterDomBy = (dom) => {
- const roomNode = dom();
-
- const center = createTemplateForComponent(Random.id(), () => import('../../../../client/views/root/DomNode'), {
- attachment: 'at-parent',
- props: () => ({ node: roomNode }),
- });
-
- appLayout.render('main', { center });
-
- return roomNode;
-};
const waitUntilRoomBeInserted = async (type, rid) => new Promise((resolve) => {
Tracker.autorun((c) => {
@@ -43,6 +30,12 @@ const waitUntilRoomBeInserted = async (type, rid) => new Promise((resolve) => {
});
});
+
+NewRoomManager.on('changed', (rid) => {
+ Session.set('openedRoom', rid);
+ RoomManager.openedRoom = rid;
+});
+
export const openRoom = async function(type, name) {
window.currentTracker && window.currentTracker.stop();
window.currentTracker = Tracker.autorun(async function(c) {
@@ -61,20 +54,15 @@ export const openRoom = async function(type, name) {
return FlowRouter.go('direct', { rid: room._id }, FlowRouter.current().queryParams);
}
+
if (room._id === Session.get('openedRoom') && !FlowRouter.getQueryParam('msg')) {
return;
}
- if (RoomManager.open(type + name).ready() !== true) {
- if (settings.get('Accounts_AllowAnonymousRead')) {
- appLayout.render('main');
- }
+ RoomManager.open(type + name);
- appLayout.render('main', { center: 'loading' });
- return;
- }
+ appLayout.render('main', { center: 'room' });
- appLayout.render('main', { center: 'loading' });
c.stop();
@@ -82,13 +70,7 @@ export const openRoom = async function(type, name) {
window.currentTracker = undefined;
}
- const roomDom = replaceCenterDomBy(() => RoomManager.getDomOfRoom(type + name, room._id, roomTypes.getConfig(type).mainTemplate));
-
- const selector = await waitUntilWrapperExists('.messages-box .wrapper');
- selector.scrollTop = roomDom.oldScrollTop;
-
- Session.set('openedRoom', room._id);
- RoomManager.openedRoom = room._id;
+ NewRoomManager.open(room._id);
fireGlobalEvent('room-opened', _.omit(room, 'usernames'));
diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js
index 87614468e85b7..a326e2391af0b 100644
--- a/app/ui/client/views/app/room.js
+++ b/app/ui/client/views/app/room.js
@@ -29,6 +29,7 @@ import { ChatMessages } from '../../lib/chatMessages';
import { fileUpload } from '../../lib/fileUpload';
import './room.html';
import { getCommonRoomEvents } from './lib/getCommonRoomEvents';
+import { RoomManager as NewRoomManager } from '../../../../../client/lib/RoomManager';
export const chatMessages = {};
@@ -787,10 +788,30 @@ Meteor.startup(() => {
if (!chatMessages[rid]) {
chatMessages[rid] = new ChatMessages();
}
+
+ const wrapper = this.find('.wrapper');
+
+ const store = NewRoomManager.getStore(rid);
+
+ const afterMessageGroup = () => {
+ if (store.scroll) {
+ wrapper.scrollTop = store.scroll;
+ } else {
+ this.sendToBottom();
+ }
+ wrapper.removeEventListener('MessageGroup', afterMessageGroup);
+
+ wrapper.addEventListener('scroll', _.throttle(() => {
+ store.update({ scroll: wrapper.scrollTop });
+ }, 100));
+ };
+
+ wrapper.addEventListener('MessageGroup', afterMessageGroup);
+
chatMessages[rid].initializeWrapper(this.find('.wrapper'));
chatMessages[rid].initializeInput(this.find('.js-input-message'), { rid });
- const wrapper = this.find('.wrapper');
+
const wrapperUl = this.find('.wrapper > ul');
const newMessage = this.find('.new-message');
diff --git a/app/utils/lib/RoomTypesCommon.js b/app/utils/lib/RoomTypesCommon.js
index 887ae2fae62aa..c34500a590401 100644
--- a/app/utils/lib/RoomTypesCommon.js
+++ b/app/utils/lib/RoomTypesCommon.js
@@ -1,5 +1,5 @@
import { Meteor } from 'meteor/meteor';
-import { Session } from 'meteor/session';
+// import { Session } from 'meteor/session';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { RoomTypeConfig } from './RoomTypeConfig';
@@ -47,7 +47,7 @@ export class RoomTypesCommon {
const routeConfig = {
name: roomConfig.route.name,
action: roomConfig.route.action,
- triggersExit: [() => Session.set('openedRoom', '')],
+ // triggersExit: [() => Session.set('openedRoom', '')],
};
if (Meteor.isClient) {
diff --git a/app/utils/lib/roomExit.js b/app/utils/lib/roomExit.js
index 35caa34a4e3c5..a7c3632b2c9c7 100644
--- a/app/utils/lib/roomExit.js
+++ b/app/utils/lib/roomExit.js
@@ -1,5 +1,5 @@
import { Blaze } from 'meteor/blaze';
-import { Session } from 'meteor/session';
+// import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';
import { FlowRouter } from 'meteor/kadira:flow-router';
@@ -25,8 +25,8 @@ export const roomExit = function() {
}
callbacks.run('roomExit');
- Session.set('lastOpenedRoom', Session.get('openedRoom'));
- Session.set('openedRoom', null);
+ // Session.set('lastOpenedRoom', Session.get('openedRoom'));
+ // Session.set('openedRoom', null);
RoomManager.openedRoom = null;
const mainNode = document.querySelector('.main-content');
diff --git a/client/components/Message/Attachments/components/Image.tsx b/client/components/Message/Attachments/components/Image.tsx
index 96af49b9f7a20..9c46a9e680399 100644
--- a/client/components/Message/Attachments/components/Image.tsx
+++ b/client/components/Message/Attachments/components/Image.tsx
@@ -15,17 +15,20 @@ type ImageProps = {
({ loadImage: true } | { loadImage: false; setLoadImage: () => void });
const getDimensions = (
- width: Dimensions['width'],
- height: Dimensions['height'],
+ originalWidth: Dimensions['width'],
+ originalHeight: Dimensions['height'],
limits: { width: number; height: number },
-): { width: 'auto' | number; height: 'auto' | number } => {
- const ratio = height / width;
+): { width: number; height: number } => {
+ const widthRatio = originalWidth / (limits.width - 4);
+ const heightRatio = originalHeight / limits.height;
- if (height >= width || Math.min(width, limits.width) * ratio > limits.height) {
- return { width: (width * Math.min(height, limits.height)) / height, height: 'auto' };
+ if (widthRatio > heightRatio) {
+ const width = Math.min(originalWidth, limits.width - 4);
+ return { width, height: (width / originalWidth) * originalHeight };
}
- return { width: Math.min(width, limits.width), height: 'auto' };
+ const height = Math.min(originalHeight, limits.height);
+ return { width: (height / originalHeight) * originalWidth, height };
};
const Image: FC = ({ previewUrl, loadImage = true, setLoadImage, src, ...size }) => {
@@ -46,22 +49,23 @@ const Image: FC = ({ previewUrl, loadImage = true, setLoadImage, src
const background = previewUrl && `url(${previewUrl}) center center / cover no-repeat fixed`;
if (!loadImage) {
- return ;
+ return ;
}
if (error) {
- return ;
+ return ;
}
return (
+ is='picture'
+ >
+
+
);
};
diff --git a/client/lib/RoomManager.ts b/client/lib/RoomManager.ts
new file mode 100644
index 0000000000000..72a59826b5e4b
--- /dev/null
+++ b/client/lib/RoomManager.ts
@@ -0,0 +1,173 @@
+import { Emitter } from '@rocket.chat/emitter';
+import { useEffect, useMemo } from 'react';
+import { useSubscription, Subscription, Unsubscribe } from 'use-subscription';
+
+import { getConfig } from '../../app/ui-utils/client/config';
+import { IRoom } from '../../definition/IRoom';
+import { useUserId, useUserRoom, useUserSubscription } from '../contexts/UserContext';
+import { useAsyncState } from '../hooks/useAsyncState';
+import { AsyncState } from './asyncState';
+
+const debug = !!(getConfig('debug') || getConfig('debug-RoomStore'));
+
+export class RoomStore extends Emitter<{
+ changed: undefined;
+}> {
+ lastTime?: Date;
+
+ scroll?: number;
+
+ constructor(readonly rid: string) {
+ super();
+
+ debug && this.on('changed', () => console.log(`RoomStore ${this.rid} changed`, this));
+ }
+
+ update({ scroll, lastTime }: { scroll?: number; lastTime?: Date }): void {
+ if (scroll !== undefined) {
+ this.scroll = scroll;
+ }
+ if (lastTime !== undefined) {
+ this.lastTime = lastTime;
+ }
+ if (scroll || lastTime) {
+ this.emit('changed');
+ }
+ }
+}
+
+const debugRoomManager = !!(getConfig('debug') || getConfig('debug-RoomManager'));
+export const RoomManager = new (class RoomManager extends Emitter<{
+ changed: IRoom['_id'] | undefined;
+ opened: IRoom['_id'];
+ closed: IRoom['_id'];
+ back: IRoom['_id'];
+ removed: IRoom['_id'];
+}> {
+ private rid: IRoom['_id'] | undefined;
+
+ private lastRid: IRoom['_id'] | undefined;
+
+ private rooms: Map = new Map();
+
+ constructor() {
+ super();
+ debugRoomManager &&
+ this.on('opened', (rid) => {
+ console.log('room opened ->', rid);
+ });
+
+ debugRoomManager &&
+ this.on('back', (rid) => {
+ console.log('room moved to back ->', rid);
+ });
+
+ debugRoomManager &&
+ this.on('closed', (rid) => {
+ console.log('room close ->', rid);
+ });
+ }
+
+ get lastOpened(): IRoom['_id'] | undefined {
+ return this.lastRid;
+ }
+
+ get opened(): IRoom['_id'] | undefined {
+ return this.rid;
+ }
+
+ visitedRooms(): IRoom['_id'][] {
+ return [...this.rooms.keys()];
+ }
+
+ back(rid: IRoom['_id']): void {
+ if (rid === this.rid) {
+ this.lastRid = rid;
+ this.rid = undefined;
+ this.emit('back', rid);
+ }
+ }
+
+ close(rid: IRoom['_id']): void {
+ if (!this.rooms.has(rid)) {
+ this.rooms.delete(rid);
+ this.emit('closed', rid);
+ }
+ this.emit('changed', this.rid);
+ }
+
+ open(rid: IRoom['_id']): void {
+ if (rid === this.rid) {
+ return;
+ }
+
+ this.back(rid);
+ if (!this.rooms.has(rid)) {
+ this.rooms.set(rid, new RoomStore(rid));
+ }
+ this.rid = rid;
+ this.emit('opened', rid);
+ this.emit('changed', this.rid);
+ }
+
+ getStore(rid: IRoom['_id']): RoomStore | undefined {
+ return this.rooms.get(rid);
+ }
+})();
+
+const subscribeVistedRooms: Subscription = {
+ getCurrentValue: () => RoomManager.visitedRooms(),
+ subscribe(callback) {
+ return RoomManager.on('changed', callback);
+ },
+};
+
+const subscribeOpenedRoom: Subscription = {
+ getCurrentValue: () => RoomManager.opened,
+ subscribe(callback) {
+ return RoomManager.on('opened', callback);
+ },
+};
+
+const fields = {};
+
+export const useHandleRoom = (rid: IRoom['_id']): AsyncState => {
+ const { resolve, update, ...state } = useAsyncState();
+ const uid = useUserId();
+ const subscription = (useUserSubscription(rid, fields) as unknown) as IRoom;
+ const _room = (useUserRoom(rid, fields) as unknown) as IRoom;
+
+ const room = uid ? subscription || _room : _room;
+
+ useEffect(() => {
+ if (room) {
+ update();
+ resolve(room);
+ }
+ }, [resolve, update, room]);
+
+ return state;
+};
+
+export const useVisitedRooms = (): IRoom['_id'][] => useSubscription(subscribeVistedRooms);
+
+export const useOpenedRoom = (): IRoom['_id'] | undefined => useSubscription(subscribeOpenedRoom);
+
+export const useRoomStore = (rid: IRoom['_id']): RoomStore => {
+ const subscribeStore: Subscription = useMemo(
+ () => ({
+ getCurrentValue: (): RoomStore | undefined => RoomManager.getStore(rid),
+ subscribe(callback): Unsubscribe {
+ return RoomManager.on('changed', callback);
+ },
+ }),
+ [rid],
+ );
+
+ const store = useSubscription(subscribeStore);
+
+ if (!store) {
+ throw new Error('Something wrong');
+ }
+ return store;
+};
diff --git a/client/sidebar/search/Row.js b/client/sidebar/search/Row.js
index 94c89abf8e1d6..c1134cd5e45e3 100644
--- a/client/sidebar/search/Row.js
+++ b/client/sidebar/search/Row.js
@@ -4,7 +4,7 @@ import SideBarItemTemplateWithData from '../RoomList/SideBarItemTemplateWithData
import UserItem from './UserItem';
const Row = ({ item, data }) => {
- const { t, SideBarItemTemplate, AvatarTemplate, useRealName, extended } = data;
+ const { t, SideBarItemTemplate, avatarTemplate: AvatarTemplate, useRealName, extended } = data;
if (item.t === 'd' && !item.u) {
return (
diff --git a/client/templates.ts b/client/templates.ts
index 6057830e9abf3..52f2752000cbd 100644
--- a/client/templates.ts
+++ b/client/templates.ts
@@ -6,11 +6,22 @@ createTemplateForComponent('MessageActions', () => import('./components/Message/
createTemplateForComponent('reactAttachments', () => import('./components/Message/Attachments'));
-createTemplateForComponent('ThreadMetric', () => import('./components/Message/Metrics/Thread'));
+createTemplateForComponent('ThreadMetric', () => import('./components/Message/Metrics/Thread'), {
+ renderContainerView: () =>
+ HTML.DIV({
+ style: 'min-height: 36px;',
+ }),
+});
createTemplateForComponent(
'DiscussionMetric',
() => import('./components/Message/Metrics/Discussion'),
+ {
+ renderContainerView: () =>
+ HTML.DIV({
+ style: 'min-height: 36px;',
+ }),
+ },
);
createTemplateForComponent(
diff --git a/client/views/room/Room.stories.js b/client/views/room/Room.stories.js
index 83b51165f0181..2e2dc933a4851 100644
--- a/client/views/room/Room.stories.js
+++ b/client/views/room/Room.stories.js
@@ -1,6 +1,6 @@
import React from 'react';
-import { RoomTemplate } from './components/RoomTemplate';
+import { RoomTemplate } from './components/RoomTemplate/RoomTemplate';
export default {
title: 'views/Room',
diff --git a/client/views/room/Room/Room.js b/client/views/room/Room/Room.js
index fda74cccaae6b..082f93b7fc6f3 100644
--- a/client/views/room/Room/Room.js
+++ b/client/views/room/Room/Room.js
@@ -5,7 +5,7 @@ import { useTranslation } from '../../../contexts/TranslationContext';
import { useUserPreference } from '../../../contexts/UserContext';
import Header from '../Header';
import BlazeTemplate from '../components/BlazeTemplate';
-import { RoomTemplate } from '../components/RoomTemplate';
+import { RoomTemplate } from '../components/RoomTemplate/RoomTemplate';
import VerticalBarOldActions from '../components/VerticalBarOldActions';
import { useRoom } from '../providers/RoomProvider';
import {
diff --git a/client/views/room/Room/RoomWithData.js b/client/views/room/Room/RoomWithData.js
index 7361055ccb8bd..11280e17b6899 100644
--- a/client/views/room/Room/RoomWithData.js
+++ b/client/views/room/Room/RoomWithData.js
@@ -1,12 +1,16 @@
import React from 'react';
+import { useOpenedRoom } from '../../../lib/RoomManager';
import RoomProvider from '../providers/RoomProvider';
import Room from './Room';
-const RoomWithData = ({ _id }) => (
-
-
-
-);
+const RoomWithData = () => {
+ const rid = useOpenedRoom();
+ return rid ? (
+
+
+
+ ) : null;
+};
export default RoomWithData;
diff --git a/client/views/room/Room/Skeleton.tsx b/client/views/room/Room/Skeleton.tsx
new file mode 100644
index 0000000000000..b6582de50cd42
--- /dev/null
+++ b/client/views/room/Room/Skeleton.tsx
@@ -0,0 +1,55 @@
+import { Skeleton, Box, InputBox } from '@rocket.chat/fuselage';
+import React, { FC, memo } from 'react';
+
+import Header from '../../../components/Header';
+import VerticalBarSkeleton from '../../../components/VerticalBar/VerticalBarSkeleton';
+import { RoomTemplate } from '../components/RoomTemplate/RoomTemplate';
+
+const RoomSkeleton: FC = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+export default memo(RoomSkeleton);
diff --git a/client/views/room/components/BlazeTemplate.js b/client/views/room/components/BlazeTemplate.js
index e80b6335f9f42..40b4c480e7cfc 100644
--- a/client/views/room/components/BlazeTemplate.js
+++ b/client/views/room/components/BlazeTemplate.js
@@ -21,7 +21,7 @@ const BlazeTemplate = ({ name, flexShrink, overflow, onClick, children, ...props
view && Blaze.remove(view);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [name]);
+ }, [name, JSON.stringify(props)]);
return (
{
- const c = flattenChildren(children);
- const header = c.filter((child) => child.type === RoomTemplate.Header);
- const body = c.filter((child) => child.type === RoomTemplate.Body);
- const footer = c.filter((child) => child.type === RoomTemplate.Footer);
- const aside = c.filter((child) => child.type === RoomTemplate.Aside);
-
- return (
-
- {header.length > 0 && header}
-
-
-
- {body}
-
- {footer.length > 0 && {footer}}
-
- {aside.length > 0 && {aside}}
-
-
- );
-};
-
-RoomTemplate.Header = function Header({ children }) {
- return children;
-};
-RoomTemplate.Body = function Body({ children }) {
- return children;
-};
-RoomTemplate.Footer = function Footer({ children }) {
- return children;
-};
-RoomTemplate.Aside = function Aside({ children }) {
- return children;
-};
-
-export default memo(RoomTemplate);
diff --git a/client/views/room/components/RoomTemplate/RoomTemplate.tsx b/client/views/room/components/RoomTemplate/RoomTemplate.tsx
new file mode 100644
index 0000000000000..682a78c55d67a
--- /dev/null
+++ b/client/views/room/components/RoomTemplate/RoomTemplate.tsx
@@ -0,0 +1,44 @@
+import { Box } from '@rocket.chat/fuselage';
+import React, { FC } from 'react';
+import flattenChildren from 'react-keyed-flatten-children';
+
+import VerticalBar from '../../../../components/VerticalBar/VerticalBar';
+import { Aside } from './slots/Aside';
+import { Body } from './slots/Body';
+import { Footer } from './slots/Footer';
+import { Header } from './slots/Header';
+
+export const RoomTemplate: FC & {
+ Header: FC;
+ Body: FC;
+ Footer: FC;
+ Aside: FC;
+} = ({ children, ...props }) => {
+ const c = flattenChildren(children);
+ const header = c.filter((child) => (child as any).type === RoomTemplate.Header);
+ const body = c.filter((child) => (child as any).type === RoomTemplate.Body);
+ const footer = c.filter((child) => (child as any).type === RoomTemplate.Footer);
+ const aside = c.filter((child) => (child as any).type === RoomTemplate.Aside);
+
+ return (
+
+ {header.length > 0 && header}
+
+
+
+ {body}
+
+ {footer.length > 0 && {footer}}
+
+ {aside.length > 0 && {aside}}
+
+
+ );
+};
+
+RoomTemplate.Header = Header;
+RoomTemplate.Body = Body;
+RoomTemplate.Footer = Footer;
+RoomTemplate.Aside = Aside;
+
+export default RoomTemplate;
diff --git a/client/views/room/components/RoomTemplate/slots/Aside.tsx b/client/views/room/components/RoomTemplate/slots/Aside.tsx
new file mode 100644
index 0000000000000..386fe26382b9f
--- /dev/null
+++ b/client/views/room/components/RoomTemplate/slots/Aside.tsx
@@ -0,0 +1,5 @@
+import React, { FC } from 'react';
+
+export const Aside: FC = function Aside({ children }) {
+ return <>{children}>;
+};
diff --git a/client/views/room/components/RoomTemplate/slots/Body.tsx b/client/views/room/components/RoomTemplate/slots/Body.tsx
new file mode 100644
index 0000000000000..7c08bb05d3e50
--- /dev/null
+++ b/client/views/room/components/RoomTemplate/slots/Body.tsx
@@ -0,0 +1,5 @@
+import React, { FC } from 'react';
+
+export const Body: FC = function Body({ children }) {
+ return <>{children}>;
+};
diff --git a/client/views/room/components/RoomTemplate/slots/Footer.tsx b/client/views/room/components/RoomTemplate/slots/Footer.tsx
new file mode 100644
index 0000000000000..a5ee444acafa3
--- /dev/null
+++ b/client/views/room/components/RoomTemplate/slots/Footer.tsx
@@ -0,0 +1,5 @@
+import React, { FC } from 'react';
+
+export const Footer: FC = function Footer({ children }) {
+ return <>{children}>;
+};
diff --git a/client/views/room/components/RoomTemplate/slots/Header.tsx b/client/views/room/components/RoomTemplate/slots/Header.tsx
new file mode 100644
index 0000000000000..f2082df2ac82f
--- /dev/null
+++ b/client/views/room/components/RoomTemplate/slots/Header.tsx
@@ -0,0 +1,5 @@
+import React, { FC } from 'react';
+
+export const Header: FC = function Header({ children }) {
+ return <>{children}>;
+};
diff --git a/client/views/room/providers/RoomProvider.tsx b/client/views/room/providers/RoomProvider.tsx
index 957ad7d73287c..d6b7268812936 100644
--- a/client/views/room/providers/RoomProvider.tsx
+++ b/client/views/room/providers/RoomProvider.tsx
@@ -1,25 +1,20 @@
-import React, { ReactNode, useContext, useMemo } from 'react';
+import React, { ReactNode, useContext, useMemo, memo } from 'react';
import { roomTypes } from '../../../../app/utils/client';
import { IRoom } from '../../../../definition/IRoom';
-import { useUserId, useUserSubscription } from '../../../contexts/UserContext';
+import { useHandleRoom } from '../../../lib/RoomManager';
+import { AsyncStatePhase } from '../../../lib/asyncState';
+import Skeleton from '../Room/Skeleton';
import { RoomContext } from '../contexts/RoomContext';
-import { useUserRoom } from '../hooks/useUserRoom';
import ToolboxProvider from './ToolboxProvider';
-const fields = {};
-
export type Props = {
children: ReactNode;
rid: IRoom['_id'];
};
const RoomProvider = ({ rid, children }: Props): JSX.Element => {
- const uid = useUserId();
- const subscription = (useUserSubscription(rid, fields) as unknown) as IRoom;
- const _room = (useUserRoom(rid, fields) as unknown) as IRoom;
-
- const room = uid ? subscription || _room : _room;
+ const { phase, value: room } = useHandleRoom(rid);
const context = useMemo(() => {
if (!room) {
return null;
@@ -31,8 +26,8 @@ const RoomProvider = ({ rid, children }: Props): JSX.Element => {
};
}, [room, rid]);
- if (!room) {
- return <>>;
+ if (phase === AsyncStatePhase.LOADING || !room) {
+ return ;
}
return (
@@ -43,4 +38,4 @@ const RoomProvider = ({ rid, children }: Props): JSX.Element => {
};
export const useRoom = (): undefined | IRoom => useContext(RoomContext)?.room;
-export default RoomProvider;
+export default memo(RoomProvider);
diff --git a/client/views/room/providers/ToolboxProvider.tsx b/client/views/room/providers/ToolboxProvider.tsx
index 924873d71b8d1..61dbfd61ac775 100644
--- a/client/views/room/providers/ToolboxProvider.tsx
+++ b/client/views/room/providers/ToolboxProvider.tsx
@@ -94,16 +94,12 @@ const ToolboxProvider = ({ children, room }: { children: ReactNode; room: IRoom
);
useLayoutEffect(() => {
- if (!(currentRoom === room._id)) {
- return;
- }
-
if (!tab) {
setActiveTabBar([undefined, undefined]);
}
setActiveTabBar([list.get(tab as string) as ToolboxActionConfig, context]);
- }, [tab, list, currentRoom, room._id, context]);
+ }, [tab, list, currentRoom, context]);
const contextValue = useMemo(
() => ({
@@ -129,7 +125,13 @@ const ToolboxProvider = ({ children, room }: { children: ReactNode; room: IRoom
(action as ToolboxActionConfig).anonymous),
)
.map(([id, item]) => (
-
+
))}
{children}
diff --git a/client/views/teams/contextualBar/channels/TeamsChannels.js b/client/views/teams/contextualBar/channels/TeamsChannels.js
index 54ee393054212..6394d941f6901 100644
--- a/client/views/teams/contextualBar/channels/TeamsChannels.js
+++ b/client/views/teams/contextualBar/channels/TeamsChannels.js
@@ -9,7 +9,7 @@ import { roomTypes } from '../../../../../app/utils/client';
import { useSetModal } from '../../../../contexts/ModalContext';
import { useRecordList } from '../../../../hooks/lists/useRecordList';
import { AsyncStatePhase } from '../../../../lib/asyncState';
-import CreateChannel from '../../../../sidebar/header/CreateChannel';
+import CreateChannelWithData from '../../../../sidebar/header/CreateChannelWithData';
import RoomInfo from '../../../room/contextualBar/Info';
import { useTabBarClose } from '../../../room/providers/ToolboxProvider';
import AddExistingModal from './AddExistingModal';
@@ -50,7 +50,7 @@ const TeamsChannels = ({ teamId }) => {
}, []);
const addExisting = useReactModal(AddExistingModal, { teamId, reload });
- const createNew = useReactModal(CreateChannel, { teamId, reload });
+ const createNew = useReactModal(CreateChannelWithData, { teamId, reload });
const goToRoom = useCallback((room) => roomTypes.openRouteLink(room.t, room), []);
const handleBack = useCallback(() => setState({}), [setState]);