diff --git a/apps/meteor/app/ui-sidenav/README.md b/apps/meteor/app/ui-sidenav/README.md deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/apps/meteor/app/ui-sidenav/client/index.js b/apps/meteor/app/ui-sidenav/client/index.js deleted file mode 100644 index 4d862bc11b774..0000000000000 --- a/apps/meteor/app/ui-sidenav/client/index.js +++ /dev/null @@ -1,3 +0,0 @@ -// import './sideNav.html'; -// import './sideNav'; -import './userPresence'; diff --git a/apps/meteor/app/ui-sidenav/client/sideNav.js b/apps/meteor/app/ui-sidenav/client/sideNav.js deleted file mode 100644 index 6bd816d01eb14..0000000000000 --- a/apps/meteor/app/ui-sidenav/client/sideNav.js +++ /dev/null @@ -1,126 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Tracker } from 'meteor/tracker'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Template } from 'meteor/templating'; - -import { SideNav, menu } from '../../ui-utils'; -import { settings } from '../../settings'; -import { getUserPreference } from '../../utils'; -import { Users } from '../../models/client'; -import { roomCoordinator } from '../../../client/lib/rooms/roomCoordinator'; - -Template.sideNav.helpers({ - dataQa() { - return Template.instance().menuState.get() === 'opened'; - }, - - flexTemplate() { - return SideNav.getFlex().template; - }, - - flexData() { - return SideNav.getFlex().data; - }, - - roomType() { - return roomCoordinator.getSortedTypes().map(({ config }) => ({ - template: config.customTemplate || 'roomList', - data: { - header: config.header, - identifier: config.identifier, - label: config.label, - }, - })); - }, - - loggedInUser() { - return !!Meteor.userId(); - }, - - // sidebarViewMode() { - // const viewMode = getUserPreference(Meteor.userId(), 'sidebarViewMode'); - // return viewMode || 'condensed'; - // }, - - // sidebarHideAvatar() { - // return !getUserPreference(Meteor.userId(), 'sidebarDisplayAvatar'); - // }, -}); - -Template.sideNav.events({ - 'click .close-flex'() { - return SideNav.closeFlex(); - }, - - 'dropped .sidebar'(e) { - return e.preventDefault(); - }, - 'mouseenter .sidebar-item__link'(e) { - const element = e.currentTarget; - setTimeout(() => { - const ellipsedElement = element.querySelector('.sidebar-item__ellipsis'); - const isTextEllipsed = ellipsedElement.offsetWidth < ellipsedElement.scrollWidth; - - if (isTextEllipsed) { - element.setAttribute('title', element.getAttribute('aria-label')); - } else { - element.removeAttribute('title'); - } - }, 0); - }, -}); - -const redirectToDefaultChannelIfNeeded = () => { - const needToBeRedirect = () => ['/', '/home'].includes(FlowRouter.current().path); - - Tracker.autorun((c) => { - const firstChannelAfterLogin = settings.get('First_Channel_After_Login'); - - if (!needToBeRedirect()) { - return c.stop(); - } - - if (!firstChannelAfterLogin) { - return c.stop(); - } - - const room = roomCoordinator.getRoomDirectives('c')?.findRoom(firstChannelAfterLogin); - - if (!room) { - return; - } - - c.stop(); - FlowRouter.go(`/channel/${firstChannelAfterLogin}`); - }); -}; - -Template.sideNav.onRendered(function () { - SideNav.init(); - menu.init(); - - this.stopMenuListener = menu.on('change', () => { - this.menuState.set(menu.isOpen() ? 'opened' : 'closed'); - }); - redirectToDefaultChannelIfNeeded(); -}); - -Template.sideNav.onDestroyed(function () { - this.stopMenuListener(); -}); -Template.sideNav.onCreated(function () { - this.groupedByType = new ReactiveVar(false); - - this.menuState = new ReactiveVar(menu.isOpen() ? 'opened' : 'closed'); - - this.autorun(() => { - const user = Users.findOne(Meteor.userId(), { - fields: { - 'settings.preferences.sidebarGroupByType': 1, - }, - }); - const userPref = getUserPreference(user, 'sidebarGroupByType'); - this.groupedByType.set(userPref || settings.get('UI_Group_Channels_By_Type')); - }); -}); diff --git a/apps/meteor/app/ui-sidenav/client/userPresence.html b/apps/meteor/app/ui-sidenav/client/userPresence.html deleted file mode 100644 index 28bfe5bc76511..0000000000000 --- a/apps/meteor/app/ui-sidenav/client/userPresence.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/apps/meteor/app/ui-sidenav/client/userPresence.js b/apps/meteor/app/ui-sidenav/client/userPresence.js deleted file mode 100644 index 6c3d17df7ae58..0000000000000 --- a/apps/meteor/app/ui-sidenav/client/userPresence.js +++ /dev/null @@ -1,59 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Accounts } from 'meteor/accounts-base'; -import { Template } from 'meteor/templating'; -import { Tracker } from 'meteor/tracker'; - -import { Presence } from '../../../client/lib/presence'; - -import './userPresence.html'; - -const data = new Map(); -const options = { - threshold: 0.1, -}; - -let lastEntries = []; -const handleEntries = function (entries) { - lastEntries = entries.filter(({ isIntersecting }) => isIntersecting); - lastEntries.forEach(async (entry) => { - const { uid } = data.get(entry.target); - Presence.get(uid); - }); -}; - -const featureExists = !!window.IntersectionObserver; - -const observer = featureExists && new IntersectionObserver(handleEntries, options); - -Tracker.autorun(() => { - // Only clear statuses on disconnect, prevent process it on reconnect again - const isConnected = Meteor.status().connected; - if (!Meteor.userId() || !isConnected) { - Presence.reset(); - return Meteor.users.update({ status: { $exists: true } }, { $unset: { status: true } }, { multi: true }); - } - - Presence.restart(); - - if (featureExists) { - for (const node of data.keys()) { - observer.unobserve(node); - observer.observe(node); - } - return; - } - - Accounts.onLogout(() => { - Presence.reset(); - }); -}); - -Template.userPresence.onRendered(function () { - if (!this.data || !this.data.uid) { - return; - } - data.set(this.firstNode, this.data); - if (featureExists) { - return observer.observe(this.firstNode); - } -}); diff --git a/apps/meteor/app/ui-sidenav/index.js b/apps/meteor/app/ui-sidenav/index.js deleted file mode 100644 index 40a7340d38877..0000000000000 --- a/apps/meteor/app/ui-sidenav/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './client/index'; diff --git a/apps/meteor/app/ui-utils/client/index.ts b/apps/meteor/app/ui-utils/client/index.ts index 9241627a7584c..a751a000fa3a0 100644 --- a/apps/meteor/app/ui-utils/client/index.ts +++ b/apps/meteor/app/ui-utils/client/index.ts @@ -1,9 +1,6 @@ import './lib/messageActionDefault'; - export { modal } from './lib/modal'; -export { SideNav } from './lib/SideNav'; export { AccountBox } from './lib/AccountBox'; -export { menu } from './lib/menu'; export { MessageAction } from './lib/MessageAction'; export { messageBox } from './lib/messageBox'; export { popover } from './lib/popover'; diff --git a/apps/meteor/app/ui-utils/client/lib/AccountBox.ts b/apps/meteor/app/ui-utils/client/lib/AccountBox.ts index 8e7d7d8137f64..264e0f84cb808 100644 --- a/apps/meteor/app/ui-utils/client/lib/AccountBox.ts +++ b/apps/meteor/app/ui-utils/client/lib/AccountBox.ts @@ -6,7 +6,6 @@ import type { TranslationKey } from '@rocket.chat/ui-contexts'; import type { Icon } from '@rocket.chat/fuselage'; import type { ComponentProps } from 'react'; -import { SideNav } from './SideNav'; import { applyDropdownActionButtonFilters } from '../../../ui-message/client/actionButtons/lib/applyButtonFilters'; import { APIClient } from '../../../utils/client'; @@ -33,35 +32,10 @@ export const isAppAccountBoxItem = (item: IAppAccountBoxItem | AccountBoxItem): export class AccountBoxBase { private items = new ReactiveVar([]); - private status = 0; - public setStatus(status: UserStatus, statusText: string): any { return APIClient.post('/v1/users.setStatus', { status, message: statusText }); } - public open(): void { - if (SideNav.flexStatus()) { - SideNav.closeFlex(); - return; - } - this.status = 1; - } - - public close(): void { - this.status = 0; - } - - public toggle(): Window | null | void { - if (this.status) { - return this.close(); - } - return this.open(); - } - - public openFlex(): void { - this.status = 0; - } - public async addItem(newItem: IAppAccountBoxItem): Promise { Tracker.nonreactive(() => { const actual = this.items.get(); diff --git a/apps/meteor/app/ui-utils/client/lib/SideNav.ts b/apps/meteor/app/ui-utils/client/lib/SideNav.ts deleted file mode 100644 index 098f9aa6f5023..0000000000000 --- a/apps/meteor/app/ui-utils/client/lib/SideNav.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Session } from 'meteor/session'; -import { Emitter } from '@rocket.chat/emitter'; - -import { Subscriptions } from '../../../models/client'; -import { RoomManager } from '../../../../client/lib/RoomManager'; -import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; - -export const SideNav = new (class extends Emitter<{ - changed: undefined; -}> { - private opened = false; - - private initiated = false; - - private openQueue: { - config: { - template?: string; - data: Record; - }; - callback: () => void; - }[] = []; - - private animating = false; - - private sideNav: JQuery; - - private flexNav: JQuery; - - toggleFlex(status: 1 | -1, callback?: () => void): void { - if (this.animating === true) { - return; - } - - this.animating = true; - - if (status === -1 || (status !== 1 && this.opened)) { - this.opened = false; - this.flexNav.addClass('animated-hidden'); - } else { - this.opened = true; - this.flexNav.removeClass('animated-hidden'); - } - - this.emit('changed'); - - !this.opened && this.setFlex(); - this.animating = false; - typeof callback === 'function' && callback(); - } - - closeFlex(callback: () => void = (): void => undefined): void { - const routeName = FlowRouter.current().route?.name; - if (!routeName || !roomCoordinator.isRouteNameKnown(routeName)) { - const subscription = Subscriptions.findOne({ rid: RoomManager.lastRid }); - if (subscription) { - roomCoordinator.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams); - } else { - FlowRouter.go('home'); - } - } - - if (this.animating === true) { - return; - } - this.toggleFlex(-1, callback); - } - - flexStatus(): boolean { - return this.opened; - } - - setFlex(template?: string, data = {}): void { - Session.set('flex-nav-template', template); - return Session.set('flex-nav-data', data); - } - - getFlex(): { - template?: string; - data: Record; - } { - return { - template: Session.get('flex-nav-template'), - data: Session.get('flex-nav-data'), - }; - } - - openFlex(callback = (): void => undefined): void { - if (!this.initiated) { - this.openQueue.push({ - config: this.getFlex(), - callback, - }); - return; - } - if (this.animating === true) { - return; - } - this.toggleFlex(1, callback); - } - - init(): void { - this.sideNav = $('.sidebar'); - this.flexNav = this.sideNav.find('.flex-nav'); - this.setFlex(''); - this.initiated = true; - if (this.openQueue.length > 0) { - this.openQueue.forEach((item) => { - this.setFlex(item.config.template, item.config.data); - return this.openFlex(item.callback); - }); - this.openQueue = []; - } - } -})(); diff --git a/apps/meteor/app/ui-utils/client/lib/menu.js b/apps/meteor/app/ui-utils/client/lib/menu.js deleted file mode 100644 index af3e1b6368b26..0000000000000 --- a/apps/meteor/app/ui-utils/client/lib/menu.js +++ /dev/null @@ -1,121 +0,0 @@ -import { Session } from 'meteor/session'; -import { Meteor } from 'meteor/meteor'; -import { Emitter } from '@rocket.chat/emitter'; - -import { isRTLScriptLanguage } from '../../../../client/lib/utils/isRTLScriptLanguage'; - -const sideNavW = 280; -const map = (x, in_min, in_max, out_min, out_max) => ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; - -export const menu = new (class extends Emitter { - constructor() { - super(); - this._open = false; - - this.sideNavW = sideNavW; - } - - get isRtl() { - return isRTLScriptLanguage(Meteor._localStorage.getItem('userLanguage')); - } - - translate(diff, width = sideNavW) { - if (diff === undefined) { - diff = this.isRtl ? -1 * sideNavW : sideNavW; - } - this.sidebarWrap.css('width', '100%'); - this.wrapper.css('overflow', 'hidden'); - this.sidebarWrap.css('background-color', '#000'); - this.sidebarWrap.css('opacity', map(Math.abs(diff) / width, 0, 1, -0.1, 0.8).toFixed(2)); - this.isRtl - ? this.sidebar.css('transform', `translate3d(${(sideNavW + diff).toFixed(3)}px, 0 , 0)`) - : this.sidebar.css('transform', `translate3d(${(diff - sideNavW).toFixed(3)}px, 0 , 0)`); - } - - init() { - this.menu = $('.sidebar'); - this.sidebar = this.menu; - this.sidebarWrap = $('.sidebar-wrap'); - this.wrapper = $('.messages-box > .wrapper'); - const ignore = (fn) => (event) => document.body.clientWidth <= 780 && fn(event); - - this.sidebarWrap.on( - 'click', - ignore((e) => { - e.target === this.sidebarWrap[0] && this.isOpen() && this.emit('clickOut', e); - }), - ); - this.on('close', () => { - this.sidebarWrap.css('width', ''); - // this.sidebarWrap.css('z-index', ''); - this.sidebarWrap.css('background-color', ''); - this.sidebar.css('transform', ''); - this.sidebar.css('box-shadow', ''); - this.sidebar.css('transition', ''); - this.sidebarWrap.css('transition', ''); - this.wrapper && this.wrapper.css('overflow', ''); - }); - this.on( - 'open', - ignore(() => { - this.sidebar.css('box-shadow', '0 0 15px 1px rgba(0,0,0,.3)'); - // this.sidebarWrap.css('z-index', '9998'); - this.translate(); - }), - ); - this.mainContent = $('.main-content'); - - this.list = $('.rooms-list'); - this._open = false; - Session.set('isMenuOpen', this._open); - } - - closePopover() { - return this.menu.find('[data-popover="anchor"]:checked').prop('checked', false).length > 0; - } - - isOpen() { - return Session.get('isMenuOpen'); - } - - open() { - this._open = true; - Session.set('isMenuOpen', this._open); - this.emit('change'); - this.emit('open'); - } - - close() { - this._open = false; - Session.set('isMenuOpen', this._open); - this.emit('change'); - this.emit('close'); - } - - toggle() { - return this.isOpen() ? this.close() : this.open(); - } -})(); - -let passClosePopover = false; - -menu.on('clickOut', function () { - if (!menu.closePopover()) { - passClosePopover = true; - menu.close(); - } -}); - -menu.on('close', function () { - if (!menu.sidebar) { - return; - } - - menu.sidebar.css('transition', ''); - menu.sidebarWrap.css('transition', ''); - if (passClosePopover) { - passClosePopover = false; - return; - } - menu.closePopover(); -}); diff --git a/apps/meteor/app/ui/client/index.ts b/apps/meteor/app/ui/client/index.ts index 6f3bb79351171..95a3acacea064 100644 --- a/apps/meteor/app/ui/client/index.ts +++ b/apps/meteor/app/ui/client/index.ts @@ -1,7 +1,6 @@ import './lib/accounts'; import './lib/collections'; import './lib/iframeCommands'; -import './lib/menu'; import './lib/parentTemplate'; import './lib/codeMirror'; import './views/app/roomSearch.html'; diff --git a/apps/meteor/app/ui/client/lib/menu.js b/apps/meteor/app/ui/client/lib/menu.js deleted file mode 100644 index 253574af13d44..0000000000000 --- a/apps/meteor/app/ui/client/lib/menu.js +++ /dev/null @@ -1,21 +0,0 @@ -import _ from 'underscore'; - -import { menu } from '../../../ui-utils'; - -window.addEventListener( - 'resize', - _.debounce( - (() => { - let lastState = window.matchMedia('(min-width: 780px)').matches ? 'mini' : 'large'; - menu.close(); - return () => { - const futureState = window.matchMedia('(min-width: 780px)').matches ? 'mini' : 'large'; - if (lastState !== futureState) { - lastState = futureState; - menu.close(); - } - }; - })(), - 100, - ), -); diff --git a/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx b/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx index 9b96cb755d49a..06c994e323fbe 100644 --- a/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx +++ b/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx @@ -5,7 +5,6 @@ import type { FC } from 'react'; import React from 'react'; import { userHasAllPermission } from '../../../app/authorization/client'; -import { SideNav } from '../../../app/ui-utils/client'; import type { AccountBoxItem } from '../../../app/ui-utils/client/lib/AccountBox'; import { getUpgradeTabLabel, isFullyFeature } from '../../../lib/upgradeTab'; import { useUpgradeTabParams } from '../../views/hooks/useUpgradeTabParams'; @@ -75,10 +74,6 @@ const AdministrationModelList: FC = ({ accountBoxI if (item.href) { FlowRouter.go(item.href); } - if (item.sideNav) { - SideNav.setFlex(item.sideNav); - SideNav.openFlex(); - } closeList(); }; diff --git a/apps/meteor/client/importPackages.ts b/apps/meteor/client/importPackages.ts index d1fc853ccc1d7..918be86ecd737 100644 --- a/apps/meteor/client/importPackages.ts +++ b/apps/meteor/client/importPackages.ts @@ -58,7 +58,6 @@ import '../app/ui-clean-history/client'; import '../app/ui-login'; import '../app/ui-master/client'; import '../app/ui-message/client'; -import '../app/ui-sidenav/client'; import '../app/ui-vrecord/client'; import '../app/videobridge/client'; import '../app/webdav/client'; diff --git a/apps/meteor/client/providers/LayoutProvider.tsx b/apps/meteor/client/providers/LayoutProvider.tsx index 6e8e7850c3453..85a33fab7a234 100644 --- a/apps/meteor/client/providers/LayoutProvider.tsx +++ b/apps/meteor/client/providers/LayoutProvider.tsx @@ -1,30 +1,37 @@ import { useBreakpoints } from '@rocket.chat/fuselage-hooks'; -import { LayoutContext, useQueryStringParameter, useSetting } from '@rocket.chat/ui-contexts'; +import { LayoutContext, useQueryStringParameter, useRoute, useSetting } from '@rocket.chat/ui-contexts'; import type { FC } from 'react'; -import React, { useMemo, useState } from 'react'; - -import { menu } from '../../app/ui-utils/client'; -import { roomCoordinator } from '../lib/rooms/roomCoordinator'; +import React, { useMemo, useState, useEffect } from 'react'; const LayoutProvider: FC = ({ children }) => { const showTopNavbarEmbeddedLayout = Boolean(useSetting('UI_Show_top_navbar_embedded_layout')); - const [isSidebarOpen, setIsSidebarOpen] = useState(false); + const [isCollapsed, setIsCollapsed] = useState(false); const layout = useQueryStringParameter('layout'); const isEmbedded = layout === 'embedded'; - const breakpoints = useBreakpoints(); - // ["xs", "sm", "md", "lg", "xl", xxl"] + const breakpoints = useBreakpoints(); // ["xs", "sm", "md", "lg", "xl", xxl"] + + const isMobile = !breakpoints.includes('md'); + + useEffect(() => { + setIsCollapsed(isMobile); + }, [isMobile]); + + const routeHome = useRoute('home'); return ( ({ - isMobile: !breakpoints.includes('md'), + isMobile, isEmbedded, showTopNavbarEmbeddedLayout, sidebar: { - isOpen: isSidebarOpen, - toggle: () => setIsSidebarOpen((isSidebarOpen) => !isSidebarOpen), + isCollapsed, + toggle: () => setIsCollapsed((isCollapsed) => !isCollapsed), + collapse: () => setIsCollapsed(true), + expand: () => setIsCollapsed(false), + close: () => (isEmbedded ? setIsCollapsed(true) : routeHome.push()), }, size: { sidebar: '240px', @@ -35,7 +42,7 @@ const LayoutProvider: FC = ({ children }) => { // eslint-disable-next-line no-nested-ternary contextualBarPosition: breakpoints.includes('sm') ? (breakpoints.includes('lg') ? 'relative' : 'absolute') : 'fixed', }), - [isEmbedded, showTopNavbarEmbeddedLayout, breakpoints, isSidebarOpen], + [isMobile, isEmbedded, showTopNavbarEmbeddedLayout, isCollapsed, breakpoints, routeHome], )} /> ); diff --git a/apps/meteor/client/sidebar/Sidebar.tsx b/apps/meteor/client/sidebar/Sidebar.tsx index 461aad174ffd0..a16432829b33a 100644 --- a/apps/meteor/client/sidebar/Sidebar.tsx +++ b/apps/meteor/client/sidebar/Sidebar.tsx @@ -100,7 +100,7 @@ const SideNav = () => { 'sidebar--main', `sidebar--${sidebarViewMode}`, sidebarHideAvatar && 'sidebar--hide-avatar', - sidebar.isOpen && isMobile && 'opened', + !sidebar.isCollapsed && isMobile && 'opened', sideBarStyle, ].filter(Boolean)} > @@ -111,7 +111,7 @@ const SideNav = () => { is='nav' className='rcx-sidebar--template' role='navigation' - data-qa-opened='{{dataQa}}' + data-qa-opened={sidebar.isCollapsed ? 'false' : 'true'} >
@@ -120,7 +120,9 @@ const SideNav = () => { - {isMobile && sidebar.toggle()}>} + {isMobile && ( + sidebar.toggle()}> + )} ); }; diff --git a/apps/meteor/client/views/account/AccountRouter.tsx b/apps/meteor/client/views/account/AccountRouter.tsx index b85cfcc09c442..abf1dd4775f75 100644 --- a/apps/meteor/client/views/account/AccountRouter.tsx +++ b/apps/meteor/client/views/account/AccountRouter.tsx @@ -2,7 +2,6 @@ import { useCurrentRoute, useRoute } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import React, { Suspense, useEffect } from 'react'; -// import { SideNav } from '../../../app/ui-utils/client'; import PageSkeleton from '../../components/PageSkeleton'; import SidenavPortal from '../../sidebar/SidenavPortal'; import AccountSidebar from './AccountSidebar'; diff --git a/apps/meteor/client/views/account/AccountSidebar.tsx b/apps/meteor/client/views/account/AccountSidebar.tsx index 9953bd04704cd..3e5971227bde8 100644 --- a/apps/meteor/client/views/account/AccountSidebar.tsx +++ b/apps/meteor/client/views/account/AccountSidebar.tsx @@ -1,43 +1,28 @@ -import { useRoutePath, useCurrentRoute, useTranslation } from '@rocket.chat/ui-contexts'; -import type { ReactElement } from 'react'; -import React, { memo, useCallback, useEffect } from 'react'; +import { useRoutePath, useCurrentRoute, useTranslation, useLayout } from '@rocket.chat/ui-contexts'; +import type { FC } from 'react'; +import React, { memo } from 'react'; import { useSyncExternalStore } from 'use-sync-external-store/shim'; -import { menu, SideNav } from '../../../app/ui-utils/client'; import Sidebar from '../../components/Sidebar'; -import { isLayoutEmbedded } from '../../lib/utils/isLayoutEmbedded'; import SettingsProvider from '../../providers/SettingsProvider'; import { getAccountSidebarItems, subscribeToAccountSidebarItems } from './sidebarItems'; -const AccountSidebar = (): ReactElement => { +const AccountSidebar: FC = () => { const t = useTranslation(); const items = useSyncExternalStore(subscribeToAccountSidebarItems, getAccountSidebarItems); - const closeFlex = useCallback(() => { - if (isLayoutEmbedded()) { - menu.close(); - return; - } - - SideNav.closeFlex(); - }, []); + const { sidebar } = useLayout(); const currentRoute = useCurrentRoute(); - const [currentRouteName, currentRouteParams, currentQueryStringParams, currentRouteGroupName] = currentRoute; + const [currentRouteName, currentRouteParams, currentQueryStringParams] = currentRoute; const currentPath = useRoutePath(currentRouteName || '', currentRouteParams, currentQueryStringParams); - useEffect(() => { - if (currentRouteGroupName !== 'account') { - SideNav.closeFlex(); - } - }, [currentRouteGroupName]); - // TODO: uplift this provider return ( - + diff --git a/apps/meteor/client/views/admin/sidebar/AdminSidebar.tsx b/apps/meteor/client/views/admin/sidebar/AdminSidebar.tsx index 535bff9c54856..c44338356cebd 100644 --- a/apps/meteor/client/views/admin/sidebar/AdminSidebar.tsx +++ b/apps/meteor/client/views/admin/sidebar/AdminSidebar.tsx @@ -1,43 +1,27 @@ -import { useRoutePath, useCurrentRoute, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRoutePath, useCurrentRoute, useTranslation, useLayout } from '@rocket.chat/ui-contexts'; import type { FC } from 'react'; -import React, { useCallback, useEffect, memo } from 'react'; +import React, { memo } from 'react'; -import { menu, SideNav } from '../../../../app/ui-utils/client'; import PlanTag from '../../../components/PlanTag'; import Sidebar from '../../../components/Sidebar'; -import { isLayoutEmbedded } from '../../../lib/utils/isLayoutEmbedded'; import SettingsProvider from '../../../providers/SettingsProvider'; import AdminSidebarPages from './AdminSidebarPages'; const AdminSidebar: FC = () => { const t = useTranslation(); - const closeAdminFlex = useCallback(() => { - if (isLayoutEmbedded()) { - menu.close(); - return; - } - - SideNav.closeFlex(); - }, []); + const { sidebar } = useLayout(); const currentRoute = useCurrentRoute(); const [currentRouteName, currentRouteParams, currentQueryStringParams] = currentRoute; const currentPath = useRoutePath(currentRouteName || '', currentRouteParams, currentQueryStringParams); - const [, , , currentRouteGroupName] = currentRoute; - - useEffect(() => { - if (currentRouteGroupName !== 'admin') { - // SideNav.toggleFlex(-1); - } - }, [currentRouteGroupName]); // TODO: uplift this provider return ( {t('Administration')} diff --git a/apps/meteor/client/views/omnichannel/OmnichannelRouter.tsx b/apps/meteor/client/views/omnichannel/OmnichannelRouter.tsx index 4b299ecbe2ecd..b3edd8458091e 100644 --- a/apps/meteor/client/views/omnichannel/OmnichannelRouter.tsx +++ b/apps/meteor/client/views/omnichannel/OmnichannelRouter.tsx @@ -4,7 +4,7 @@ import React, { Suspense, useEffect } from 'react'; import PageSkeleton from '../../components/PageSkeleton'; import SidenavPortal from '../../sidebar/SidenavPortal'; -import OminichannelSidebar from './sidebar/OmnichannelSidebar'; +import OmnichannelSidebar from './sidebar/OmnichannelSidebar'; type OmnichannelRouterProps = { children?: ReactNode; @@ -24,7 +24,7 @@ const OmnichannelRouter = ({ children }: OmnichannelRouterProps): ReactElement = <> }>{children} - + ) : ( diff --git a/apps/meteor/client/views/omnichannel/sidebar/OmnichannelSidebar.tsx b/apps/meteor/client/views/omnichannel/sidebar/OmnichannelSidebar.tsx index c6bde13d40826..2501d5cba4d80 100644 --- a/apps/meteor/client/views/omnichannel/sidebar/OmnichannelSidebar.tsx +++ b/apps/meteor/client/views/omnichannel/sidebar/OmnichannelSidebar.tsx @@ -1,12 +1,10 @@ -import { useRoutePath, useCurrentRoute, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRoutePath, useCurrentRoute, useTranslation, useLayout } from '@rocket.chat/ui-contexts'; import type { FC } from 'react'; -import React, { useCallback, useEffect, memo } from 'react'; +import React, { memo } from 'react'; import { useSyncExternalStore } from 'use-sync-external-store/shim'; -import { menu, SideNav } from '../../../../app/ui-utils/client'; import Sidebar from '../../../components/Sidebar'; import SidebarItemsAssemblerProps from '../../../components/Sidebar/SidebarItemsAssembler'; -import { isLayoutEmbedded } from '../../../lib/utils/isLayoutEmbedded'; import SettingsProvider from '../../../providers/SettingsProvider'; import { getOmnichannelSidebarItems, subscribeToOmnichannelSidebarItems } from '../sidebarItems'; @@ -14,29 +12,16 @@ const OmnichannelSidebar: FC = () => { const items = useSyncExternalStore(subscribeToOmnichannelSidebarItems, getOmnichannelSidebarItems); const t = useTranslation(); - const closeOmnichannelFlex = useCallback(() => { - if (isLayoutEmbedded()) { - menu.close(); - return; - } - - SideNav.closeFlex(); - }, []); + const { sidebar } = useLayout(); const currentRoute = useCurrentRoute(); - const [currentRouteName, currentRouteParams, currentQueryStringParams, currentRouteGroupName] = currentRoute; + const [currentRouteName, currentRouteParams, currentQueryStringParams] = currentRoute; const currentPath = useRoutePath(currentRouteName ?? '', currentRouteParams, currentQueryStringParams); - useEffect(() => { - if (currentRouteGroupName !== 'omnichannel') { - // SideNav.closeFlex(); - } - }, [currentRouteGroupName]); - return ( - {t('Omnichannel')}} /> + {t('Omnichannel')}} /> diff --git a/apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx b/apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx index c78394a027d95..c9845e7df8efb 100644 --- a/apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx +++ b/apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx @@ -1,11 +1,9 @@ import { Box } from '@rocket.chat/fuselage'; -import { useLayout, useCurrentRoute, useRoutePath, useSetting, useCurrentModal } from '@rocket.chat/ui-contexts'; +import { useLayout, useCurrentRoute, useRoutePath, useSetting, useCurrentModal, useRoute } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; -import React, { useCallback } from 'react'; +import React, { useEffect, useRef } from 'react'; -import { useReactiveValue } from '../../../hooks/useReactiveValue'; import Sidebar from '../../../sidebar'; -import BlazeTemplate from '../BlazeTemplate'; const LayoutWithSidebar = ({ children }: { children: ReactNode }): ReactElement => { const { isEmbedded: embeddedLayout } = useLayout(); @@ -13,11 +11,33 @@ const LayoutWithSidebar = ({ children }: { children: ReactNode }): ReactElement const modal = useCurrentModal(); const currentRoutePath = useRoutePath(currentRouteName, currentParameters); - const removeSidenav = useReactiveValue( - useCallback(() => embeddedLayout && !currentRoutePath?.startsWith('/admin'), [currentRoutePath, embeddedLayout]), - ); + const channelRoute = useRoute('channel'); + const removeSidenav = embeddedLayout && !currentRoutePath?.startsWith('/admin'); const readReceiptsEnabled = useSetting('Message_Read_Receipt_Store_Users'); + const firstChannelAfterLogin = useSetting('First_Channel_After_Login'); + + const redirected = useRef(false); + + useEffect(() => { + const needToBeRedirect = currentRoutePath && ['/', '/home'].includes(currentRoutePath); + + if (!needToBeRedirect) { + return; + } + + if (!firstChannelAfterLogin || typeof firstChannelAfterLogin !== 'string') { + return; + } + + if (redirected.current) { + return; + } + redirected.current = true; + + channelRoute.push({ name: firstChannelAfterLogin }); + }, [channelRoute, currentRoutePath, firstChannelAfterLogin]); + return ( true, }, - '../../../app/ui-utils/client': { - SideNav: {}, - }, '../../../app/ui-utils/client/lib/AccountBox': { AccountBoxItem: {}, isAppAccountBoxItem: () => false, diff --git a/apps/meteor/tests/unit/client/components/AdministrationList/AdministrationModelList.spec.tsx b/apps/meteor/tests/unit/client/components/AdministrationList/AdministrationModelList.spec.tsx index a9db32cad7075..1d88a460c4894 100644 --- a/apps/meteor/tests/unit/client/components/AdministrationList/AdministrationModelList.spec.tsx +++ b/apps/meteor/tests/unit/client/components/AdministrationList/AdministrationModelList.spec.tsx @@ -9,7 +9,6 @@ import RouterContextMock from '../../../../mocks/client/RouterContextMock'; const COMPONENT_PATH = '../../../../../client/components/AdministrationList/AdministrationModelList'; const defaultConfig = { '../../../app/ui-utils/client': { - 'SideNav': {}, '@noCallThru': true, }, 'meteor/kadira:flow-router': { @@ -139,13 +138,6 @@ describe('components/AdministrationList/AdministrationModelList', () => { const openFlex = spy(); const AdministrationModelList = proxyquire.load(COMPONENT_PATH, { ...defaultConfig, - '../../../app/ui-utils/client': { - 'SideNav': { - setFlex, - openFlex, - }, - '@noCallThru': true, - }, }).default; render( , diff --git a/packages/ui-contexts/src/LayoutContext.ts b/packages/ui-contexts/src/LayoutContext.ts index 0bfd009cedef4..31d278875bba3 100644 --- a/packages/ui-contexts/src/LayoutContext.ts +++ b/packages/ui-contexts/src/LayoutContext.ts @@ -9,7 +9,13 @@ export type LayoutContextValue = { isEmbedded: boolean; showTopNavbarEmbeddedLayout: boolean; isMobile: boolean; - sidebar: any; + sidebar: { + isCollapsed: boolean; + toggle: () => void; + collapse: () => void; + expand: () => void; + close: () => void; + } size: SizeLayout; contextualBarExpanded: boolean; contextualBarPosition: 'absolute' | 'relative' | 'fixed'; @@ -19,7 +25,13 @@ export const LayoutContext = createContext({ isEmbedded: false, showTopNavbarEmbeddedLayout: false, isMobile: false, - sidebar: {}, + sidebar: { + isCollapsed: false, + toggle: () => { }, + collapse: () => { }, + expand: () => { }, + close: () => { }, + }, size: { sidebar: '380px', contextualBar: '380px',