diff --git a/apps/meteor/app/mail-messages/server/functions/sendMail.ts b/apps/meteor/app/mail-messages/server/functions/sendMail.ts index 325fb5e24934..881b5eb7f706 100644 --- a/apps/meteor/app/mail-messages/server/functions/sendMail.ts +++ b/apps/meteor/app/mail-messages/server/functions/sendMail.ts @@ -8,7 +8,7 @@ import { Users } from '@rocket.chat/models'; import { placeholders } from '../../../utils/server'; import { SystemLogger } from '../../../../server/lib/logger/system'; import * as Mailer from '../../../mailer/server/api'; -import { generatePath } from '../../../../lib/router'; +import { generatePath } from '../../../../lib/utils/generatePath'; export const sendMail = async function ({ from, diff --git a/apps/meteor/app/ui-utils/client/lib/AccountBox.ts b/apps/meteor/app/ui-utils/client/lib/AccountBox.ts index 334eb60ac820..e75fb03dde88 100644 --- a/apps/meteor/app/ui-utils/client/lib/AccountBox.ts +++ b/apps/meteor/app/ui-utils/client/lib/AccountBox.ts @@ -2,7 +2,7 @@ import type { IUIActionButton, IUActionButtonWhen } from '@rocket.chat/apps-engi import type { UserStatus } from '@rocket.chat/core-typings'; import { ReactiveVar } from 'meteor/reactive-var'; import { Tracker } from 'meteor/tracker'; -import type { RouterPaths, TranslationKey } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths, TranslationKey } from '@rocket.chat/ui-contexts'; import type { Icon } from '@rocket.chat/fuselage'; import type { ComponentProps } from 'react'; @@ -22,7 +22,7 @@ export interface IAppAccountBoxItem extends IUIActionButton { export type AccountBoxItem = { name: TranslationKey; icon: ComponentProps['name']; - href: RouterPaths[keyof RouterPaths]['pathname']; + href: IRouterPaths[keyof IRouterPaths]['pathname']; sideNav?: string; condition: () => boolean; }; diff --git a/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx b/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx index 0cf9a3bfc806..6bff76b97a67 100644 --- a/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx +++ b/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx @@ -1,5 +1,5 @@ import { OptionTitle } from '@rocket.chat/fuselage'; -import { useTranslation, useRoute, useMethod, useSetModal, useRole, useNavigate } from '@rocket.chat/ui-contexts'; +import { useTranslation, useRoute, useMethod, useSetModal, useRole, useRouter } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { FC } from 'react'; import React from 'react'; @@ -34,7 +34,7 @@ const AdministrationModelList: FC = ({ accountBoxI setModal(); }; - const navigate = useNavigate(); + const router = useRouter(); const upgradeRoute = useRoute('upgrade'); const cloudRoute = useRoute('cloud'); const showUpgradeItem = !isLoading && tabType; @@ -79,7 +79,7 @@ const AdministrationModelList: FC = ({ accountBoxI role='listitem' text={t('Workspace')} onClick={() => { - navigate('/admin'); + router.navigate('/admin'); onDismiss(); }} /> @@ -89,7 +89,7 @@ const AdministrationModelList: FC = ({ accountBoxI {accountBoxItems.map((item, key) => { const action = () => { if (item.href) { - navigate(item.href); + router.navigate(item.href); } onDismiss(); }; diff --git a/apps/meteor/client/components/GazzodownText.tsx b/apps/meteor/client/components/GazzodownText.tsx index bc42241a09c2..d35ba8722b6a 100644 --- a/apps/meteor/client/components/GazzodownText.tsx +++ b/apps/meteor/client/components/GazzodownText.tsx @@ -2,11 +2,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; import type { ChannelMention, UserMention } from '@rocket.chat/gazzodown'; import { MarkupInteractionContext } from '@rocket.chat/gazzodown'; import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { useLayout, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useLayout, useRouter, useUserPreference } from '@rocket.chat/ui-contexts'; import type { UIEvent } from 'react'; import React, { useCallback, memo, useMemo } from 'react'; -import { generatePath } from '../../lib/router'; import { detectEmoji } from '../lib/utils/detectEmoji'; import { fireGlobalEvent } from '../lib/utils/fireGlobalEvent'; import { useChat } from '../views/room/contexts/ChatContext'; @@ -85,12 +84,14 @@ const GazzodownText = ({ mentions, channels, searchText, children }: GazzodownTe const resolveChannelMention = useCallback((mention: string) => channels?.find(({ name }) => name === mention), [channels]); + const router = useRouter(); + const onChannelMentionClick = useCallback( ({ _id: rid }: ChannelMention) => (event: UIEvent): void => { if (isEmbedded) { fireGlobalEvent('click-mention-link', { - path: generatePath('/channel/:name', { name: rid }), + path: router.getRoutePath('/channel/:name/:tab?/:context?', { name: rid }), channel: rid, }); } @@ -98,7 +99,7 @@ const GazzodownText = ({ mentions, channels, searchText, children }: GazzodownTe event.stopPropagation(); goToRoom(rid); }, - [isEmbedded, goToRoom], + [router, isEmbedded, goToRoom], ); return ( diff --git a/apps/meteor/client/components/NotFoundState.tsx b/apps/meteor/client/components/NotFoundState.tsx index 8a17051ab368..421fa1a9ca87 100644 --- a/apps/meteor/client/components/NotFoundState.tsx +++ b/apps/meteor/client/components/NotFoundState.tsx @@ -1,5 +1,5 @@ import { Box, States, StatesAction, StatesActions, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage'; -import { useNavigate, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; @@ -10,10 +10,10 @@ type NotFoundProps = { const NotFoundState = ({ title, subtitle }: NotFoundProps): ReactElement => { const t = useTranslation(); - const navigate = useNavigate(); + const router = useRouter(); const handleGoHomeClick = () => { - navigate('/home'); + router.navigate('/home'); }; return ( diff --git a/apps/meteor/client/lib/createRouteGroup.tsx b/apps/meteor/client/lib/createRouteGroup.tsx index 2d3cb4bb67f7..7e6c67c81204 100644 --- a/apps/meteor/client/lib/createRouteGroup.tsx +++ b/apps/meteor/client/lib/createRouteGroup.tsx @@ -1,4 +1,4 @@ -import type { RouterPaths } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths } from '@rocket.chat/ui-contexts'; import type { Context, Current, @@ -27,7 +27,7 @@ const registerLazyComponentRoute = , - path: TrimPrefix>, + path: TrimPrefix>, { component: RouteComponent, props, @@ -112,7 +112,7 @@ export const createRouteGroup = ( }, ): [register: () => void, unregister: () => void]; >( - path: TrimPrefix>, + path: TrimPrefix>, options: RouteOptions & { component: ElementType; props?: Record; @@ -120,7 +120,7 @@ export const createRouteGroup = ( }, ): [register: () => void, unregister: () => void]; >( - path: TrimPrefix>, + path: TrimPrefix>, options: RouteOptions, ): void; } => { @@ -131,7 +131,7 @@ export const createRouteGroup = ( function registerRoute(path: '/' | '', options: RouteOptions<`${TGroupName}-index`>): [register: () => void, unregister: () => void]; function registerRoute>( - path: TrimPrefix>, + path: TrimPrefix>, options: RouteOptions & { component: ElementType; props?: Record; @@ -139,11 +139,11 @@ export const createRouteGroup = ( }, ): [register: () => void, unregister: () => void]; function registerRoute>( - path: TrimPrefix>, + path: TrimPrefix>, options: RouteOptions, ): void; function registerRoute>( - path: TrimPrefix>, + path: TrimPrefix>, options: | RouteOptions | (RouteOptions & { diff --git a/apps/meteor/client/lib/createSidebarItems.ts b/apps/meteor/client/lib/createSidebarItems.ts index d7010f06b090..6e50a721772c 100644 --- a/apps/meteor/client/lib/createSidebarItems.ts +++ b/apps/meteor/client/lib/createSidebarItems.ts @@ -1,10 +1,10 @@ import type { IconProps } from '@rocket.chat/fuselage'; -import type { RouterPaths } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; export type Item = { i18nLabel: string; - href?: RouterPaths[keyof RouterPaths]['pathname'] | `https://go.rocket.chat/i/${string}`; + href?: IRouterPaths[keyof IRouterPaths]['pathname'] | `https://go.rocket.chat/i/${string}`; icon?: IconProps['name']; tag?: 'Alpha' | 'Beta'; permissionGranted?: () => boolean; diff --git a/apps/meteor/client/lib/rooms/roomCoordinator.tsx b/apps/meteor/client/lib/rooms/roomCoordinator.tsx index a8247ee7b18f..b680f3cd4788 100644 --- a/apps/meteor/client/lib/rooms/roomCoordinator.tsx +++ b/apps/meteor/client/lib/rooms/roomCoordinator.tsx @@ -1,6 +1,6 @@ import type { IRoom, RoomType, IUser, AtLeast, ValueOf, ISubscription } from '@rocket.chat/core-typings'; import { isRoomFederated } from '@rocket.chat/core-typings'; -import type { RouterPaths } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths } from '@rocket.chat/ui-contexts'; import { FlowRouter } from 'meteor/kadira:flow-router'; import React from 'react'; @@ -167,7 +167,7 @@ class RoomCoordinatorClient extends RoomCoordinator { return true; } - private validateRoute(route: IRoomTypeRouteConfig): void { + private validateRoute(route: IRoomTypeRouteConfig): void { const { name, path, link } = route; if (typeof name !== 'string' || name.length === 0) { diff --git a/apps/meteor/client/providers/CallProvider/CallProvider.tsx b/apps/meteor/client/providers/CallProvider/CallProvider.tsx index 068dc34d1e2b..adf09e94af2e 100644 --- a/apps/meteor/client/providers/CallProvider/CallProvider.tsx +++ b/apps/meteor/client/providers/CallProvider/CallProvider.tsx @@ -21,7 +21,7 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { Random } from '@rocket.chat/random'; import type { Device, IExperimentalHTMLAudioElement } from '@rocket.chat/ui-contexts'; import { - useNavigate, + useRouter, useUser, useSetting, useEndpoint, @@ -88,7 +88,7 @@ export const CallProvider: FC = ({ children }) => { const result = useVoipClient(); const user = useUser(); - const navigate = useNavigate(); + const router = useRouter(); const setOutputMediaDevice = useSetOutputMediaDevice(); const setInputMediaDevice = useSetInputMediaDevice(); @@ -110,14 +110,14 @@ export const CallProvider: FC = ({ children }) => { token: roomInfo.v.token || '', options: { comment: data?.comment, tags: data?.tags }, })); - navigate('/home'); + router.navigate('/home'); const queueAggregator = result.voipClient?.getAggregator(); if (queueAggregator) { queueAggregator.callEnded(); } }, - [navigate, result?.voipClient, roomInfo, voipCloseRoomEndpoint], + [router, result?.voipClient, roomInfo, voipCloseRoomEndpoint], ); const openWrapUpModal = useCallback((): void => { diff --git a/apps/meteor/client/providers/LayoutProvider.tsx b/apps/meteor/client/providers/LayoutProvider.tsx index 1786ba94493a..9ea67a9f24de 100644 --- a/apps/meteor/client/providers/LayoutProvider.tsx +++ b/apps/meteor/client/providers/LayoutProvider.tsx @@ -1,5 +1,5 @@ import { useBreakpoints } from '@rocket.chat/fuselage-hooks'; -import { LayoutContext, useNavigate, useQueryStringParameter, useSetting } from '@rocket.chat/ui-contexts'; +import { LayoutContext, useRouter, useQueryStringParameter, useSetting } from '@rocket.chat/ui-contexts'; import type { FC } from 'react'; import React, { useMemo, useState, useEffect } from 'react'; @@ -16,7 +16,7 @@ const LayoutProvider: FC = ({ children }) => { setIsCollapsed(isMobile); }, [isMobile]); - const navigate = useNavigate(); + const router = useRouter(); return ( { toggle: () => setIsCollapsed((isCollapsed) => !isCollapsed), collapse: () => setIsCollapsed(true), expand: () => setIsCollapsed(false), - close: () => (isEmbedded ? setIsCollapsed(true) : navigate('/home')), + close: () => (isEmbedded ? setIsCollapsed(true) : router.navigate('/home')), }, size: { sidebar: '240px', @@ -41,7 +41,7 @@ const LayoutProvider: FC = ({ children }) => { // eslint-disable-next-line no-nested-ternary contextualBarPosition: breakpoints.includes('sm') ? (breakpoints.includes('lg') ? 'relative' : 'absolute') : 'fixed', }), - [isMobile, isEmbedded, showTopNavbarEmbeddedLayout, isCollapsed, breakpoints, navigate], + [isMobile, isEmbedded, showTopNavbarEmbeddedLayout, isCollapsed, breakpoints, router], )} /> ); diff --git a/apps/meteor/client/providers/RouterProvider.tsx b/apps/meteor/client/providers/RouterProvider.tsx index f6d61d8ff598..6dcb4a7523be 100644 --- a/apps/meteor/client/providers/RouterProvider.tsx +++ b/apps/meteor/client/providers/RouterProvider.tsx @@ -1,4 +1,4 @@ -import type { RouterContextValue, RouterPaths } from '@rocket.chat/ui-contexts'; +import type { RouterContextValue, RouterPathPattern, RouterPathName } from '@rocket.chat/ui-contexts'; import { RouterContext } from '@rocket.chat/ui-contexts'; import { FlowRouter } from 'meteor/kadira:flow-router'; import { Tracker } from 'meteor/tracker'; @@ -7,6 +7,12 @@ import React from 'react'; import { createSubscription } from '../lib/createSubscription'; +const getRoutePath = ( + patternOrName: RouterPathPattern | RouterPathName, + parameters?: Record, + search?: Record, +): string => Tracker.nonreactive(() => FlowRouter.path(patternOrName, parameters, search)); + export const navigate = ( toOrDelta: | string @@ -103,8 +109,8 @@ const pushRoute = ( const queryParams = typeof queryStringParameters === 'function' ? queryStringParameters(FlowRouter.current().queryParams) : queryStringParameters; navigate({ - pathname: name, - params: parameters, + pattern: name, + params: parameters ?? {}, search: queryParams, }); }; @@ -118,8 +124,8 @@ const replaceRoute = ( typeof queryStringParameters === 'function' ? queryStringParameters(FlowRouter.current().queryParams) : queryStringParameters; navigate( { - pathname: name, - params: parameters, + pattern: name, + params: parameters ?? {}, search: queryParams, }, { replace: true }, @@ -149,20 +155,17 @@ const setQueryString = (paramsOrFn: Record | ((prev: Reco FlowRouter.setQueryParams(paramsOrFn); }; -const getRoutePath = (name: keyof RouterPaths, parameters?: Record, queryStringParameters?: Record) => - Tracker.nonreactive(() => FlowRouter.path(name, parameters, queryStringParameters)); - const contextValue = { + getRoutePath, + navigate, queryRoutePath, queryRouteUrl, - navigate, pushRoute, replaceRoute, queryRouteParameter, queryQueryStringParameter, queryCurrentRoute, setQueryString, - getRoutePath, }; const RouterProvider: FC = ({ children }) => ; diff --git a/apps/meteor/client/sidebar/RoomMenu.tsx b/apps/meteor/client/sidebar/RoomMenu.tsx index b8c6e97ac1f0..be8d889f3065 100644 --- a/apps/meteor/client/sidebar/RoomMenu.tsx +++ b/apps/meteor/client/sidebar/RoomMenu.tsx @@ -3,7 +3,7 @@ import { Option, Menu } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey, Fields } from '@rocket.chat/ui-contexts'; import { - useNavigate, + useRouter, useSetModal, useToastMessageDispatch, useUserSubscription, @@ -77,7 +77,7 @@ const RoomMenu = ({ const closeModal = useMutableCallback(() => setModal()); - const navigate = useNavigate(); + const router = useRouter(); const subscription = useUserSubscription(rid, fields); const canFavorite = useSetting('Favorite_Rooms'); @@ -115,7 +115,7 @@ const RoomMenu = ({ try { await leaveRoom({ roomId: rid }); if (roomOpen) { - navigate('/home'); + router.navigate('/home'); } LegacyRoomManager.close(rid); } catch (error) { @@ -184,7 +184,7 @@ const RoomMenu = ({ } LegacyRoomManager.close(subscription.t + subscription.name); - navigate('/home'); + router.navigate('/home'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/sidebar/header/UserDropdown.tsx b/apps/meteor/client/sidebar/header/UserDropdown.tsx index e654429e80f3..a858627cf3b9 100644 --- a/apps/meteor/client/sidebar/header/UserDropdown.tsx +++ b/apps/meteor/client/sidebar/header/UserDropdown.tsx @@ -14,7 +14,7 @@ import { } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useNavigate, useLayout, useLogout, useSetting, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRouter, useLayout, useLogout, useSetting, useTranslation } from '@rocket.chat/ui-contexts'; import { useThemeMode } from '@rocket.chat/ui-theming/src/hooks/useThemeMode'; import type { ReactElement } from 'react'; import React from 'react'; @@ -54,7 +54,7 @@ type UserDropdownProps = { const UserDropdown = ({ user, onClose }: UserDropdownProps): ReactElement => { const t = useTranslation(); - const navigate = useNavigate(); + const router = useRouter(); const logout = useLogout(); const { isMobile } = useLayout(); const presenceDisabled = useSetting('Presence_broadcast_disabled'); @@ -80,7 +80,7 @@ const UserDropdown = ({ user, onClose }: UserDropdownProps): ReactElement => { }); const handleMyAccount = useMutableCallback(() => { - navigate('/account'); + router.navigate('/account'); onClose(); }); diff --git a/apps/meteor/client/sidebar/header/actions/Directory.tsx b/apps/meteor/client/sidebar/header/actions/Directory.tsx index 485b36103ee4..cdfdcfc1eaf1 100644 --- a/apps/meteor/client/sidebar/header/actions/Directory.tsx +++ b/apps/meteor/client/sidebar/header/actions/Directory.tsx @@ -1,17 +1,17 @@ import { Sidebar } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { useLayout, useNavigate } from '@rocket.chat/ui-contexts'; +import { useLayout, useRouter } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; type DirectoryProps = Omit, 'is'>; const Directory = (props: DirectoryProps) => { - const navigate = useNavigate(); + const router = useRouter(); const { sidebar } = useLayout(); const handleDirectory = useMutableCallback(() => { sidebar.toggle(); - navigate('/directory'); + router.navigate('/directory'); }); return ; diff --git a/apps/meteor/client/sidebar/header/actions/Home.tsx b/apps/meteor/client/sidebar/header/actions/Home.tsx index b657bc4ebaa6..2c4bbec40f51 100644 --- a/apps/meteor/client/sidebar/header/actions/Home.tsx +++ b/apps/meteor/client/sidebar/header/actions/Home.tsx @@ -1,16 +1,16 @@ import { Sidebar } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { useNavigate, useLayout, useSetting } from '@rocket.chat/ui-contexts'; +import { useRouter, useLayout, useSetting } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes, VFC } from 'react'; import React from 'react'; const SidebarHeaderActionHome: VFC, 'is'>> = (props) => { - const navigate = useNavigate(); + const router = useRouter(); const { sidebar } = useLayout(); const showHome = useSetting('Layout_Show_Home_Button'); const handleHome = useMutableCallback(() => { sidebar.toggle(); - navigate('/home'); + router.navigate('/home'); }); return showHome ? : null; diff --git a/apps/meteor/client/startup/routes.tsx b/apps/meteor/client/startup/routes.tsx index 3223c1053cb6..131067d5ae6d 100644 --- a/apps/meteor/client/startup/routes.tsx +++ b/apps/meteor/client/startup/routes.tsx @@ -1,5 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; -import type { RouterPaths } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths } from '@rocket.chat/ui-contexts'; import { Accounts } from 'meteor/accounts-base'; import { FlowRouter } from 'meteor/kadira:flow-router'; import { Meteor } from 'meteor/meteor'; @@ -40,8 +40,7 @@ const OAuthErrorPage = lazy(() => import('../views/oauth/OAuthErrorPage')); FlowRouter.wait(); declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'index': { pathname: '/'; pattern: '/'; @@ -141,7 +140,7 @@ FlowRouter.route('/', { setTimeout(async () => { const user = Meteor.user() as IUser | null; if (user?.defaultRoom) { - const room = user.defaultRoom.split('/') as [routeName: keyof RouterPaths, routeParam: string]; + const room = user.defaultRoom.split('/') as [routeName: keyof IRouterPaths, routeParam: string]; navigate({ pattern: room[0], params: { name: room[1] }, diff --git a/apps/meteor/client/views/account/AccountRouter.tsx b/apps/meteor/client/views/account/AccountRouter.tsx index 53bc5070d443..5c68f27e1917 100644 --- a/apps/meteor/client/views/account/AccountRouter.tsx +++ b/apps/meteor/client/views/account/AccountRouter.tsx @@ -1,4 +1,4 @@ -import { useCurrentRoute, useNavigate } from '@rocket.chat/ui-contexts'; +import { useCurrentRoute, useRouter } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import React, { Suspense, useEffect } from 'react'; @@ -12,15 +12,15 @@ type AccountRouterProps = { const AccountRouter = ({ children }: AccountRouterProps): ReactElement => { const [routeName] = useCurrentRoute(); - const navigate = useNavigate(); + const router = useRouter(); useEffect(() => { if (routeName !== 'account-index') { return; } - navigate('/account/profile', { replace: true }); - }, [routeName, navigate]); + router.navigate('/account/profile', { replace: true }); + }, [routeName, router]); return children ? ( <> diff --git a/apps/meteor/client/views/account/routes.tsx b/apps/meteor/client/views/account/routes.tsx index 2e275593dad2..d31287fa7a57 100644 --- a/apps/meteor/client/views/account/routes.tsx +++ b/apps/meteor/client/views/account/routes.tsx @@ -3,8 +3,7 @@ import { lazy } from 'react'; import { createRouteGroup } from '../../lib/createRouteGroup'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'account-index': { pathname: '/account'; pattern: '/account'; diff --git a/apps/meteor/client/views/admin/AdministrationRouter.tsx b/apps/meteor/client/views/admin/AdministrationRouter.tsx index f12283a4b05a..d63c807e002d 100644 --- a/apps/meteor/client/views/admin/AdministrationRouter.tsx +++ b/apps/meteor/client/views/admin/AdministrationRouter.tsx @@ -1,4 +1,4 @@ -import { useNavigate, useCurrentRoute, useRoute } from '@rocket.chat/ui-contexts'; +import { useRouter, useCurrentRoute, useRoute } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import React, { Suspense, useEffect } from 'react'; @@ -31,7 +31,7 @@ const AdministrationRouter = ({ children }: AdministrationRouterProps): ReactEle const [routeName] = useCurrentRoute(); const upgradeRoute = useRoute('upgrade'); - const navigate = useNavigate(); + const router = useRouter(); useEffect(() => { if (routeName !== 'admin-index') { @@ -50,8 +50,8 @@ const AdministrationRouter = ({ children }: AdministrationRouterProps): ReactEle return; } - navigate(defaultRoutePath, { replace: true }); - }, [upgradeRoute, routeName, tabType, trialEndDate, isLoading, navigate]); + router.navigate(defaultRoutePath, { replace: true }); + }, [upgradeRoute, routeName, tabType, trialEndDate, isLoading, router]); return ( diff --git a/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx b/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx index 3ccdf4e8365e..72141b9e2aef 100644 --- a/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx +++ b/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx @@ -1,6 +1,6 @@ import { Button, ButtonGroup, Table } from '@rocket.chat/fuselage'; import { useMediaQuery } from '@rocket.chat/fuselage-hooks'; -import { useToastMessageDispatch, useEndpoint, useTranslation, useNavigate } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useEndpoint, useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import React, { useMemo } from 'react'; @@ -19,7 +19,7 @@ function ImportHistoryPage() { const getCurrentImportOperation = useEndpoint('GET', '/v1/getCurrentImportOperation'); const getLatestImportOperations = useEndpoint('GET', '/v1/getLatestImportOperations'); - const navigate = useNavigate(); + const router = useRouter(); const currentOperation = useQuery( ['ImportHistoryPage', 'currentOperation'], @@ -50,7 +50,7 @@ function ImportHistoryPage() { }, [latestOperations.isSuccess, latestOperations.data]); const handleNewImportClick = () => { - navigate('/admin/import/new'); + router.navigate('/admin/import/new'); }; const downloadPendingFilesResult = useMutation({ @@ -68,7 +68,7 @@ function ImportHistoryPage() { } dispatchToastMessage({ type: 'info', message: t('File_Downloads_Started') }); - navigate('/admin/import/progress'); + router.navigate('/admin/import/progress'); }, }); @@ -87,7 +87,7 @@ function ImportHistoryPage() { } dispatchToastMessage({ type: 'info', message: t('File_Downloads_Started') }); - navigate('/admin/import/progress'); + router.navigate('/admin/import/progress'); }, }); diff --git a/apps/meteor/client/views/admin/import/ImportOperationSummary.js b/apps/meteor/client/views/admin/import/ImportOperationSummary.js index 76ca247cc4da..0a963ea82d72 100644 --- a/apps/meteor/client/views/admin/import/ImportOperationSummary.js +++ b/apps/meteor/client/views/admin/import/ImportOperationSummary.js @@ -1,5 +1,5 @@ import { Table } from '@rocket.chat/fuselage'; -import { useNavigate, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo } from 'react'; import { @@ -55,16 +55,16 @@ function ImportOperationSummary({ const canCheckProgress = useMemo(() => valid && ImportingStartedStates.includes(status), [valid, status]); - const navigate = useNavigate(); + const router = useRouter(); const handleClick = () => { if (canContinue) { - navigate('/admin/import/prepare'); + router.navigate('/admin/import/prepare'); return; } if (canCheckProgress) { - navigate('/admin/import/progress'); + router.navigate('/admin/import/progress'); } }; diff --git a/apps/meteor/client/views/admin/import/ImportProgressPage.tsx b/apps/meteor/client/views/admin/import/ImportProgressPage.tsx index 4cba00ba48d0..d0274ab15111 100644 --- a/apps/meteor/client/views/admin/import/ImportProgressPage.tsx +++ b/apps/meteor/client/views/admin/import/ImportProgressPage.tsx @@ -1,6 +1,6 @@ import { Box, Margins, Throbber } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { useToastMessageDispatch, useEndpoint, useTranslation, useStream, useNavigate } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useEndpoint, useTranslation, useStream, useRouter } from '@rocket.chat/ui-contexts'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import React, { useEffect } from 'react'; @@ -17,7 +17,7 @@ const ImportProgressPage = function ImportProgressPage() { const dispatchToastMessage = useToastMessageDispatch(); const handleError = useErrorHandler(); - const navigate = useNavigate(); + const router = useRouter(); const getCurrentImportOperation = useEndpoint('GET', '/v1/getCurrentImportOperation'); const getImportProgress = useEndpoint('GET', '/v1/getImportProgress'); @@ -42,23 +42,23 @@ const ImportProgressPage = function ImportProgressPage() { refetchInterval: 1000, onSuccess: ({ valid, status }) => { if (!valid) { - navigate('/admin/import'); + router.navigate('/admin/import'); return; } if (status === 'importer_done') { dispatchToastMessage({ type: 'success', message: t('Importer_done') }); - navigate('/admin/import'); + router.navigate('/admin/import'); return; } if (!(ImportingStartedStates as string[]).includes(status)) { - navigate('/admin/import/prepare'); + router.navigate('/admin/import/prepare'); } }, onError: (error) => { handleError(error, t('Failed_To_Load_Import_Data')); - navigate('/admin/import'); + router.navigate('/admin/import'); }, }, ); @@ -81,13 +81,13 @@ const ImportProgressPage = function ImportProgressPage() { type: 'success', message: t(message), }); - navigate('/admin/import'); + router.navigate('/admin/import'); return; case 'importer_import_failed': case 'importer_import_cancelled': t.has(message) && handleError(message); - navigate('/admin/import'); + router.navigate('/admin/import'); return; default: @@ -113,7 +113,7 @@ const ImportProgressPage = function ImportProgressPage() { onSuccess: (progress) => { if (!progress) { dispatchToastMessage({ type: 'warning', message: t('Importer_not_in_progress') }); - navigate('/admin/import/prepare'); + router.navigate('/admin/import/prepare'); return; } @@ -129,7 +129,7 @@ const ImportProgressPage = function ImportProgressPage() { }, onError: (error) => { handleError(error, t('Failed_To_Load_Import_Data')); - navigate('/admin/import'); + router.navigate('/admin/import'); }, }, ); diff --git a/apps/meteor/client/views/admin/import/NewImportPage.js b/apps/meteor/client/views/admin/import/NewImportPage.js index eef5ef51e8cc..926664d3e290 100644 --- a/apps/meteor/client/views/admin/import/NewImportPage.js +++ b/apps/meteor/client/views/admin/import/NewImportPage.js @@ -14,11 +14,10 @@ import { UrlInput, } from '@rocket.chat/fuselage'; import { useUniqueId, useSafely } from '@rocket.chat/fuselage-hooks'; -import { useToastMessageDispatch, useRouteParameter, useSetting, useEndpoint, useTranslation, useNavigate } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useRouter, useRouteParameter, useSetting, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useState, useMemo, useEffect } from 'react'; import { Importers } from '../../../../app/importer/client/index'; -import { generatePath } from '../../../../lib/router'; import Page from '../../../components/Page'; import { useFormatMemorySize } from '../../../hooks/useFormatMemorySize'; import { useErrorHandler } from './useErrorHandler'; @@ -35,25 +34,25 @@ function NewImportPage() { const maxFileSize = useSetting('FileUpload_MaxFileSize'); - const navigate = useNavigate(); + const router = useRouter(); const uploadImportFile = useEndpoint('POST', '/v1/uploadImportFile'); const downloadPublicImportFile = useEndpoint('POST', '/v1/downloadPublicImportFile'); useEffect(() => { if (importerKey && !importer) { - navigate('/admin/import/new', { replace: true }); + router.navigate('/admin/import/new', { replace: true }); } - }, [importer, importerKey, navigate]); + }, [importer, importerKey, router]); const formatMemorySize = useFormatMemorySize(); const handleBackToImportsButtonClick = () => { - navigate('/admin/import'); + router.navigate('/admin/import'); }; const handleImporterKeyChange = (importerKey) => { - navigate(generatePath('/admin/import/new/:importerKey', { importerKey }), { replace: true }); + router.navigate(router.getRoutePath('/admin/import/new/:importerKey', { importerKey }), { replace: true }); }; const handleFileTypeChange = (fileType) => { @@ -105,7 +104,7 @@ function NewImportPage() { }), ), ); - navigate('/admin/import/prepare'); + router.navigate('/admin/import/prepare'); } finally { setLoading(false); } @@ -123,7 +122,7 @@ function NewImportPage() { try { await downloadPublicImportFile({ importerKey, fileUrl }); dispatchToastMessage({ type: 'success', message: t('Import_requested_successfully') }); - navigate('/admin/import/prepare'); + router.navigate('/admin/import/prepare'); } catch (error) { handleError(error, t('Failed_To_upload_Import_File')); } finally { @@ -143,7 +142,7 @@ function NewImportPage() { try { await downloadPublicImportFile({ importerKey, fileUrl: filePath }); dispatchToastMessage({ type: 'success', message: t('Import_requested_successfully') }); - navigate('/admin/import/prepare'); + router.navigate('/admin/import/prepare'); } catch (error) { handleError(error, t('Failed_To_upload_Import_File')); } finally { diff --git a/apps/meteor/client/views/admin/import/PrepareImportPage.js b/apps/meteor/client/views/admin/import/PrepareImportPage.js index 293134d60170..59e05b5f85d0 100644 --- a/apps/meteor/client/views/admin/import/PrepareImportPage.js +++ b/apps/meteor/client/views/admin/import/PrepareImportPage.js @@ -1,6 +1,6 @@ import { Badge, Box, Button, ButtonGroup, Icon, Margins, Throbber, Tabs } from '@rocket.chat/fuselage'; import { useDebouncedValue, useSafely } from '@rocket.chat/fuselage-hooks'; -import { useEndpoint, useTranslation, useStream, useNavigate } from '@rocket.chat/ui-contexts'; +import { useEndpoint, useTranslation, useStream, useRouter } from '@rocket.chat/ui-contexts'; import React, { useEffect, useState, useMemo } from 'react'; import { @@ -48,7 +48,7 @@ function PrepareImportPage() { const usersCount = useMemo(() => users.filter(({ do_import }) => do_import).length, [users]); const channelsCount = useMemo(() => channels.filter(({ do_import }) => do_import).length, [channels]); - const navigate = useNavigate(); + const router = useRouter(); const getImportFileData = useEndpoint('GET', '/v1/getImportFileData'); const getCurrentImportOperation = useEndpoint('GET', '/v1/getCurrentImportOperation'); @@ -71,13 +71,13 @@ function PrepareImportPage() { if (!data) { handleError(t('Importer_not_setup')); - navigate('/admin/import'); + router.navigate('/admin/import'); return; } if (data.step) { handleError(t('Failed_To_Load_Import_Data')); - navigate('/admin/import'); + router.navigate('/admin/import'); return; } @@ -88,7 +88,7 @@ function PrepareImportPage() { setProgressRate(null); } catch (error) { handleError(error, t('Failed_To_Load_Import_Data')); - navigate('/admin/import'); + router.navigate('/admin/import'); } }; @@ -100,12 +100,12 @@ function PrepareImportPage() { ); if (!operation.valid) { - navigate('/admin/import/new'); + router.navigate('/admin/import/new'); return; } if (ImportingStartedStates.includes(operation.status)) { - navigate('/admin/import/progress'); + router.navigate('/admin/import/progress'); return; } @@ -121,28 +121,28 @@ function PrepareImportPage() { if (ImportingErrorStates.includes(operation.status)) { handleError(t('Import_Operation_Failed')); - navigate('/admin/import'); + router.navigate('/admin/import'); return; } if (operation.status === ProgressStep.DONE) { - navigate('/admin/import'); + router.navigate('/admin/import'); return; } handleError(t('Unknown_Import_State')); - navigate('/admin/import'); + router.navigate('/admin/import'); } catch (error) { handleError(t('Failed_To_Load_Import_Data')); - navigate('/admin/import'); + router.navigate('/admin/import'); } }; loadCurrentOperation(); - }, [getCurrentImportOperation, getImportFileData, handleError, navigate, setMessageCount, setPreparing, setProgressRate, setStatus, t]); + }, [getCurrentImportOperation, getImportFileData, handleError, router, setMessageCount, setPreparing, setProgressRate, setStatus, t]); const handleBackToImportsButtonClick = () => { - navigate('/admin/import'); + router.navigate('/admin/import'); }; const handleStartButtonClick = async () => { @@ -150,10 +150,10 @@ function PrepareImportPage() { try { await startImport({ input: { users, channels } }); - navigate('/admin/import/progress'); + router.navigate('/admin/import/progress'); } catch (error) { handleError(error, t('Failed_To_Start_Import')); - navigate('/admin/import'); + router.navigate('/admin/import'); } }; diff --git a/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/InviteUsers.tsx b/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/InviteUsers.tsx index 253d93fc8ba5..0e35f6e5bac4 100644 --- a/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/InviteUsers.tsx +++ b/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/InviteUsers.tsx @@ -1,14 +1,14 @@ import { Box, ButtonGroup, Button, Banner } from '@rocket.chat/fuselage'; -import { useNavigate, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import type { FC, ReactElement } from 'react'; import React from 'react'; const InviteUsers: FC<{ onClose: () => void }> = ({ onClose }): ReactElement => { const t = useTranslation(); - const navigate = useNavigate(); + const router = useRouter(); const handleDirectory = (): void => { onClose(); - navigate('/directory/users'); + router.navigate('/directory/users'); }; return ( diff --git a/apps/meteor/client/views/admin/routes.tsx b/apps/meteor/client/views/admin/routes.tsx index 3cd324b11796..354604c3bb11 100644 --- a/apps/meteor/client/views/admin/routes.tsx +++ b/apps/meteor/client/views/admin/routes.tsx @@ -4,8 +4,7 @@ import type { UpgradeTabVariant } from '../../../lib/upgradeTab'; import { createRouteGroup } from '../../lib/createRouteGroup'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'admin-index': { pathname: '/admin'; pattern: '/admin'; diff --git a/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx b/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx index 3f9f1aee48be..63037a4d0bc6 100644 --- a/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx +++ b/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx @@ -3,7 +3,7 @@ import { css } from '@rocket.chat/css-in-js'; import { Button, Box } from '@rocket.chat/fuselage'; import { Card } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useRoute, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; @@ -24,7 +24,7 @@ type SettingsGroupCardProps = { const SettingsGroupCard = ({ id, title, description }: SettingsGroupCardProps): ReactElement => { const t = useTranslation(); - const router = useRoute('admin-settings'); + const router = useRouter(); return ( @@ -35,7 +35,7 @@ const SettingsGroupCard = ({ id, title, description }: SettingsGroupCardProps): - diff --git a/apps/meteor/client/views/directory/DirectoryPage.tsx b/apps/meteor/client/views/directory/DirectoryPage.tsx index 56ee9203380a..625163367aa1 100644 --- a/apps/meteor/client/views/directory/DirectoryPage.tsx +++ b/apps/meteor/client/views/directory/DirectoryPage.tsx @@ -1,5 +1,5 @@ import { Tabs } from '@rocket.chat/fuselage'; -import { useCurrentRoute, useNavigate, useRouteParameter, useSetting, useTranslation } from '@rocket.chat/ui-contexts'; +import { useCurrentRoute, useRouter, useRouteParameter, useSetting, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useEffect, useCallback } from 'react'; @@ -17,7 +17,7 @@ const DirectoryPage = (): ReactElement => { const federationEnabled = useSetting('FEDERATION_Enabled'); const [routeName] = useCurrentRoute(); const tab = useRouteParameter('tab') as TabName | undefined; - const navigate = useNavigate(); + const router = useRouter(); useEffect(() => { if (routeName !== 'directory') { @@ -25,11 +25,11 @@ const DirectoryPage = (): ReactElement => { } if (!tab || (tab === 'external' && !federationEnabled)) { - navigate(`/directory/${defaultTab}`, { replace: true }); + router.navigate(`/directory/${defaultTab}`, { replace: true }); } - }, [routeName, navigate, tab, federationEnabled, defaultTab]); + }, [routeName, router, tab, federationEnabled, defaultTab]); - const handleTabClick = useCallback((tab: TabName) => () => navigate(`/directory/${tab}`), [navigate]); + const handleTabClick = useCallback((tab: TabName) => () => router.navigate(`/directory/${tab}`), [router]); return ( diff --git a/apps/meteor/client/views/home/cards/JoinRoomsCard.tsx b/apps/meteor/client/views/home/cards/JoinRoomsCard.tsx index 2483aac72e1a..1a105ea8d58f 100644 --- a/apps/meteor/client/views/home/cards/JoinRoomsCard.tsx +++ b/apps/meteor/client/views/home/cards/JoinRoomsCard.tsx @@ -1,15 +1,15 @@ import { Button } from '@rocket.chat/fuselage'; import { Card } from '@rocket.chat/ui-client'; -import { useTranslation, useNavigate } from '@rocket.chat/ui-contexts'; +import { useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; const JoinRoomsCard = (): ReactElement => { const t = useTranslation(); - const navigate = useNavigate(); + const router = useRouter(); const handleDirectory = (): void => { - navigate('/directory'); + router.navigate('/directory'); }; return ( diff --git a/apps/meteor/client/views/invite/SecretURLPage.tsx b/apps/meteor/client/views/invite/SecretURLPage.tsx index f61ae12c74e7..20cca5787bc9 100644 --- a/apps/meteor/client/views/invite/SecretURLPage.tsx +++ b/apps/meteor/client/views/invite/SecretURLPage.tsx @@ -1,17 +1,17 @@ -import { useUserId, useNavigate } from '@rocket.chat/ui-contexts'; +import { useUserId, useRouter } from '@rocket.chat/ui-contexts'; import RegistrationPageRouter from '@rocket.chat/web-ui-registration'; import type { ReactElement } from 'react'; import React, { useEffect } from 'react'; const SecretURLPage = (): ReactElement | null => { const uid = useUserId(); - const navigate = useNavigate(); + const router = useRouter(); useEffect(() => { if (uid) { - navigate('/home'); + router.navigate('/home'); } - }, [uid, navigate]); + }, [uid, router]); if (uid) { return null; diff --git a/apps/meteor/client/views/marketplace/routes.tsx b/apps/meteor/client/views/marketplace/routes.tsx index 90b6d75b6b0e..881f955b1018 100644 --- a/apps/meteor/client/views/marketplace/routes.tsx +++ b/apps/meteor/client/views/marketplace/routes.tsx @@ -3,8 +3,7 @@ import { lazy } from 'react'; import { createRouteGroup } from '../../lib/createRouteGroup'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'marketplace-index': { pattern: '/marketplace'; pathname: '/marketplace'; diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.tsx b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.tsx index a36fdd6946cf..77bcbff7b5bf 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.tsx +++ b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.tsx @@ -1,6 +1,6 @@ import { Box, Margins, ButtonGroup, Button, Icon, Divider } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import type { RouterPaths } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths } from '@rocket.chat/ui-contexts'; import { useToastMessageDispatch, useCurrentRoute, useRoute, useTranslation, useEndpoint, usePermission } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import React from 'react'; @@ -23,7 +23,7 @@ import { FormSkeleton } from '../../components/FormSkeleton'; type ContactInfoProps = { id: string; rid?: string; - route?: keyof RouterPaths; + route?: keyof IRouterPaths; }; const ContactInfo = ({ id: contactId, rid: roomId = '', route }: ContactInfoProps) => { diff --git a/apps/meteor/client/views/omnichannel/routes.ts b/apps/meteor/client/views/omnichannel/routes.ts index ce3f12457f2b..9d2ed96e8b1f 100644 --- a/apps/meteor/client/views/omnichannel/routes.ts +++ b/apps/meteor/client/views/omnichannel/routes.ts @@ -3,8 +3,7 @@ import { lazy } from 'react'; import { createRouteGroup } from '../../lib/createRouteGroup'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'omnichannel-index': { pattern: '/omnichannel'; pathname: '/omnichannel'; diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx index 5579e0129bcc..c8b642e56d96 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx @@ -10,7 +10,7 @@ import { useEndpoint, useMethod, useTranslation, - useNavigate, + useRouter, } from '@rocket.chat/ui-contexts'; import React, { useCallback, useState, useEffect } from 'react'; @@ -38,7 +38,7 @@ export const useQuickActions = ( getAction: (id: string) => void; } => { const setModal = useSetModal(); - const navigate = useNavigate(); + const router = useRouter(); const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); @@ -166,14 +166,14 @@ export const useQuickActions = ( try { await forwardChat(transferData); dispatchToastMessage({ type: 'success', message: t('Transferred') }); - navigate('/home'); + router.navigate('/home'); LegacyRoomManager.close(room.t + rid); closeModal(); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } }, - [closeModal, dispatchToastMessage, forwardChat, room.t, rid, navigate, t], + [closeModal, dispatchToastMessage, forwardChat, room.t, rid, router, t], ); const closeChat = useEndpoint('POST', '/v1/livechat/room.closeByUser'); @@ -213,7 +213,7 @@ export const useQuickActions = ( const returnChatToQueueMutation = useReturnChatToQueueMutation({ onSuccess: () => { LegacyRoomManager.close(room.t + rid); - navigate('/home'); + router.navigate('/home'); }, onError: (error) => { dispatchToastMessage({ type: 'error', message: error }); diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js index 88b7a91169f8..90234643f353 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js @@ -24,7 +24,7 @@ import { useRole, useMethod, useTranslation, - useNavigate, + useRouter, } from '@rocket.chat/ui-contexts'; import React, { useCallback, useMemo, useRef } from 'react'; @@ -134,7 +134,7 @@ function EditChannel({ room, onClickClose, onClickBack }) { const maxAgeDefault = useSetting(`RetentionPolicy_MaxAge_${typeMap[room.t]}`) || 30; const saveData = useRef({}); - const navigate = useNavigate(); + const router = useRouter(); const onChange = useCallback(({ initialValue, value, key }) => { const { current } = saveData; @@ -277,7 +277,7 @@ function EditChannel({ room, onClickClose, onClickBack }) { const onConfirm = async () => { await deleteRoom(room._id); onCancel(); - navigate('/home'); + router.navigate('/home'); }; setModal( diff --git a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomDelete.tsx b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomDelete.tsx index 6c82818e9095..b812e896bab9 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomDelete.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomDelete.tsx @@ -1,7 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { isRoomFederated } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { useSetModal, useToastMessageDispatch, useTranslation, useEndpoint, usePermission, useNavigate } from '@rocket.chat/ui-contexts'; +import { useSetModal, useToastMessageDispatch, useTranslation, useEndpoint, usePermission, useRouter } from '@rocket.chat/ui-contexts'; import React from 'react'; import GenericModal from '../../../../../../components/GenericModal'; @@ -11,7 +11,7 @@ export const useRoomDelete = (room: IRoom, resetState?: () => void) => { const t = useTranslation(); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); - const navigate = useNavigate(); + const router = useRouter(); const hasPermissionToDelete = usePermission(room.t === 'c' ? 'delete-c' : 'delete-p', room._id); const canDelete = isRoomFederated(room) ? false : hasPermissionToDelete; @@ -27,7 +27,7 @@ export const useRoomDelete = (room: IRoom, resetState?: () => void) => { return resetState(); } - navigate('/home'); + router.navigate('/home'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomHide.tsx b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomHide.tsx index 090455496070..fde85f426396 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomHide.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomHide.tsx @@ -1,7 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useSetModal, useToastMessageDispatch, useMethod, useTranslation, useNavigate } from '@rocket.chat/ui-contexts'; +import { useSetModal, useToastMessageDispatch, useMethod, useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import React from 'react'; import { UiTextContext } from '../../../../../../../definition/IRoomTypeConfig'; @@ -13,13 +13,13 @@ export const useRoomHide = (room: IRoom) => { const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); const hideRoom = useMethod('hideRoom'); - const navigate = useNavigate(); + const router = useRouter(); const handleHide = useMutableCallback(async () => { const hide = async () => { try { await hideRoom(room._id); - navigate('/home'); + router.navigate('/home'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx index 53ee603af0c3..6b842c1fc173 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx @@ -1,7 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useNavigate, useSetModal, useToastMessageDispatch, useMethod, useTranslation, usePermission } from '@rocket.chat/ui-contexts'; +import { useRouter, useSetModal, useToastMessageDispatch, useMethod, useTranslation, usePermission } from '@rocket.chat/ui-contexts'; import React from 'react'; import { LegacyRoomManager } from '../../../../../../../app/ui-utils/client'; @@ -15,7 +15,7 @@ export const useRoomLeave = (room: IRoom, joined = true) => { const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); const leaveRoom = useMethod('leaveRoom'); - const navigate = useNavigate(); + const router = useRouter(); const canLeave = usePermission(room.t === 'c' ? 'leave-c' : 'leave-p') && room.cl !== false && joined; @@ -23,7 +23,7 @@ export const useRoomLeave = (room: IRoom, joined = true) => { const leaveAction = async () => { try { await leaveRoom(room._id); - navigate('/home'); + router.navigate('/home'); LegacyRoomManager.close(room._id); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); diff --git a/apps/meteor/client/views/room/providers/RoomProvider.tsx b/apps/meteor/client/views/room/providers/RoomProvider.tsx index 94e3ed4ccdea..b2935f4702ea 100644 --- a/apps/meteor/client/views/room/providers/RoomProvider.tsx +++ b/apps/meteor/client/views/room/providers/RoomProvider.tsx @@ -1,6 +1,6 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { isOmnichannelRoom } from '@rocket.chat/core-typings'; -import { usePermission, useStream, useUserId, useNavigate } from '@rocket.chat/ui-contexts'; +import { usePermission, useStream, useUserId, useRouter } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ReactNode, ContextType, ReactElement } from 'react'; import React, { useMemo, memo, useEffect, useCallback } from 'react'; @@ -49,12 +49,12 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { }, [subscribeToRoom, rid, queryClient, room]); // TODO: the following effect is a workaround while we don't have a general and definitive solution for it - const navigate = useNavigate(); + const router = useRouter(); useEffect(() => { if (isSuccess && !room) { - navigate('/home'); + router.navigate('/home'); } - }, [isSuccess, room, navigate]); + }, [isSuccess, room, router]); // TODO: Review the necessity of this effect when we move away from cached collections useEffect(() => { diff --git a/apps/meteor/client/views/setupWizard/hooks/useRouteLock.ts b/apps/meteor/client/views/setupWizard/hooks/useRouteLock.ts index 712bd380b30a..e771dea6eeb5 100644 --- a/apps/meteor/client/views/setupWizard/hooks/useRouteLock.ts +++ b/apps/meteor/client/views/setupWizard/hooks/useRouteLock.ts @@ -1,5 +1,5 @@ import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; -import { useUserId, useUser, useSetting, useRole, useNavigate } from '@rocket.chat/ui-contexts'; +import { useUserId, useUser, useSetting, useRole, useRouter } from '@rocket.chat/ui-contexts'; import { useEffect, useState } from 'react'; export const useRouteLock = (): boolean => { @@ -8,7 +8,7 @@ export const useRouteLock = (): boolean => { const userId = useUserId(); const user = useDebouncedValue(useUser(), 100); const hasAdminRole = useRole('admin'); - const navigate = useNavigate(); + const router = useRouter(); useEffect(() => { if (!setupWizardState) { @@ -26,12 +26,12 @@ export const useRouteLock = (): boolean => { const mustRedirect = isComplete || noUserLoggedInAndIsNotPending || userIsLoggedInButIsNotAdmin; if (mustRedirect) { - navigate('/home'); + router.navigate('/home'); return; } setLocked(false); - }, [navigate, setupWizardState, userId, user, hasAdminRole, locked]); + }, [router, setupWizardState, userId, user, hasAdminRole, locked]); return locked; }; diff --git a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js index 2cbebf3677d4..8044d15d9380 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js +++ b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js @@ -7,7 +7,7 @@ import { usePermission, useMethod, useTranslation, - useNavigate, + useRouter, } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; @@ -61,7 +61,7 @@ const TeamsInfoWithLogic = ({ room, openEditing }) => { const hideTeam = useMethod('hideRoom'); - const navigate = useNavigate(); + const router = useRouter(); const canDelete = usePermission('delete-team', room._id); const canEdit = usePermission('edit-team-channel', room._id); @@ -75,7 +75,7 @@ const TeamsInfoWithLogic = ({ room, openEditing }) => { try { await deleteTeam({ teamId: room.teamId, ...(roomsToRemove.length && { roomsToRemove }) }); dispatchToastMessage({ type: 'success', message: t('Team_has_been_deleted') }); - navigate('/home'); + router.navigate('/home'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { @@ -97,7 +97,7 @@ const TeamsInfoWithLogic = ({ room, openEditing }) => { ...(roomsToLeave.length && { rooms: roomsToLeave }), }); dispatchToastMessage({ type: 'success', message: t('Teams_left_team_successfully') }); - navigate('/home'); + router.navigate('/home'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { @@ -112,7 +112,7 @@ const TeamsInfoWithLogic = ({ room, openEditing }) => { const hide = async () => { try { await hideTeam(room._id); - navigate('/home'); + router.navigate('/home'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { diff --git a/apps/meteor/definition/IRoomTypeConfig.ts b/apps/meteor/definition/IRoomTypeConfig.ts index bb35c0fd72b3..718894d7f445 100644 --- a/apps/meteor/definition/IRoomTypeConfig.ts +++ b/apps/meteor/definition/IRoomTypeConfig.ts @@ -11,13 +11,13 @@ import type { } from '@rocket.chat/core-typings'; import type { ComponentProps } from 'react'; import type { Icon } from '@rocket.chat/fuselage'; -import type { RouterPaths } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths } from '@rocket.chat/ui-contexts'; export type RoomIdentification = { rid?: IRoom['_id']; name?: string; tab?: string }; -export interface IRoomTypeRouteConfig { +export interface IRoomTypeRouteConfig { name: TRouteName; - path?: RouterPaths[TRouteName]['pattern']; + path?: IRouterPaths[TRouteName]['pattern']; link?: (data: RoomIdentification) => Record; } @@ -57,7 +57,7 @@ export const UiTextContext = { export interface IRoomTypeConfig { identifier: string; - route?: IRoomTypeRouteConfig; + route?: IRoomTypeRouteConfig; } export interface IRoomTypeClientConfig extends IRoomTypeConfig { diff --git a/apps/meteor/definition/externals/meteor/kadira-flow-router.d.ts b/apps/meteor/definition/externals/meteor/kadira-flow-router.d.ts index de7aa2c31f38..43f67aff9b46 100644 --- a/apps/meteor/definition/externals/meteor/kadira-flow-router.d.ts +++ b/apps/meteor/definition/externals/meteor/kadira-flow-router.d.ts @@ -1,14 +1,14 @@ declare module 'meteor/kadira:flow-router' { import type { Subscription } from 'meteor/meteor'; - import type { RouterPaths } from '@rocket.chat/ui-contexts'; + import type { IRouterPaths, RouterPathName, RouterPathPattern } from '@rocket.chat/ui-contexts'; - type RouteName = keyof RouterPaths; + type RouteName = keyof IRouterPaths; type GroupName = RouteName extends infer U ? (U extends `${infer TGroupName}-index` ? TGroupName : never) : never; - type GroupPrefix = RouterPaths[`${TGroupName}-index`]['pattern']; + type GroupPrefix = IRouterPaths[`${TGroupName}-index`]['pattern']; type RouteNamesOf = Extract< | keyof { - [TRouteName in RouteName as RouterPaths[TRouteName]['pattern'] extends `${GroupPrefix}/${string}` + [TRouteName in RouteName as IRouterPaths[TRouteName]['pattern'] extends `${GroupPrefix}/${string}` ? TRouteName : never]: Route; } @@ -34,11 +34,11 @@ declare module 'meteor/kadira:flow-router' { }; class Route | undefined = any> { - constructor(router: Router, pathDef: RouterPaths[TRouteName]['pattern'], options?: RouteOptions, group?: TGroup); + constructor(router: Router, pathDef: IRouterPaths[TRouteName]['pattern'], options?: RouteOptions, group?: TGroup); options: RouteOptions; - pathDef: RouterPaths[TRouteName]['pattern']; + pathDef: IRouterPaths[TRouteName]['pattern']; path: string; @@ -91,7 +91,7 @@ declare module 'meteor/kadira:flow-router' { parent: TParentGroup; route>( - pathDef: TrimPrefix>, + pathDef: TrimPrefix>, options: RouteOptions, group?: TParentGroup, ): Route; @@ -118,23 +118,23 @@ declare module 'meteor/kadira:flow-router' { constructor(); route( - pathDef: RouterPaths[TRouteName]['pattern'], + pathDef: IRouterPaths[TRouteName]['pattern'], options: RouteOptions, ): Route; route>( - pathDef: RouterPaths[TRouteName]['pattern'], + pathDef: IRouterPaths[TRouteName]['pattern'], options: RouteOptions, group: TGroup, ): Route; group(options: GroupOptions): Group; - path(pathDef: RouteName, fields?: Record, queryParams?: Record): string; + path(pathDef: RouterPathName | RouterPathPattern, fields?: Record, queryParams?: Record): string; - url(pathDef: string, fields?: Record, queryParams?: Record): string; + url(pathDef: string, fields?: Record, queryParams?: Record): string; - go(pathDef: string, fields?: Record, queryParams?: Record): void; + go(pathDef: string, fields?: Record, queryParams?: Record): void; reload(): void; diff --git a/apps/meteor/ee/client/omnichannel/routes.ts b/apps/meteor/ee/client/omnichannel/routes.ts index 0797011dad0c..3efe8d6aab22 100644 --- a/apps/meteor/ee/client/omnichannel/routes.ts +++ b/apps/meteor/ee/client/omnichannel/routes.ts @@ -3,8 +3,7 @@ import { lazy } from 'react'; import { registerOmnichannelRoute } from '../../../client/views/omnichannel/routes'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'omnichannel-monitors': { pattern: '/omnichannel/monitors'; pathname: '/omnichannel/monitors'; diff --git a/apps/meteor/ee/client/startup/audit.tsx b/apps/meteor/ee/client/startup/audit.tsx index c6de0c82b4d0..ee451fb82b34 100644 --- a/apps/meteor/ee/client/startup/audit.tsx +++ b/apps/meteor/ee/client/startup/audit.tsx @@ -12,8 +12,7 @@ const AuditPage = lazy(() => import('../views/audit/AuditPage')); const AuditLogPage = lazy(() => import('../views/audit/AuditLogPage')); declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'audit-home': { pathname: '/audit'; pattern: '/audit/:tab?'; diff --git a/apps/meteor/ee/client/startup/deviceManagement.ts b/apps/meteor/ee/client/startup/deviceManagement.ts index dccc8dcdbdd6..33f1a99dd767 100644 --- a/apps/meteor/ee/client/startup/deviceManagement.ts +++ b/apps/meteor/ee/client/startup/deviceManagement.ts @@ -6,8 +6,7 @@ import { registerAdminRoute, registerAdminSidebarItem, unregisterAdminSidebarIte import { onToggledFeature } from '../lib/onToggledFeature'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'device-management': { pathname: `/admin/device-management${`/${string}` | ''}${`/${string}` | ''}`; pattern: '/admin/device-management/:context?/:id?'; diff --git a/apps/meteor/ee/client/startup/engagementDashboard.ts b/apps/meteor/ee/client/startup/engagementDashboard.ts index 27605834d200..0bd1d4995169 100644 --- a/apps/meteor/ee/client/startup/engagementDashboard.ts +++ b/apps/meteor/ee/client/startup/engagementDashboard.ts @@ -6,8 +6,7 @@ import { registerAdminRoute, registerAdminSidebarItem, unregisterAdminSidebarIte import { onToggledFeature } from '../lib/onToggledFeature'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface RouterPaths { + interface IRouterPaths { 'engagement-dashboard': { pattern: '/admin/engagement-dashboard/:tab?'; pathname: `/admin/engagement-dashboard${`/${string}` | ''}`; diff --git a/apps/meteor/lib/rooms/roomTypes/direct.ts b/apps/meteor/lib/rooms/roomTypes/direct.ts index 84cbcceac4c5..8d8764380196 100644 --- a/apps/meteor/lib/rooms/roomTypes/direct.ts +++ b/apps/meteor/lib/rooms/roomTypes/direct.ts @@ -2,8 +2,7 @@ import type { IRoomTypeConfig } from '../../../definition/IRoomTypeConfig'; import type { RoomCoordinator } from '../coordinator'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - export interface RouterPaths { + export interface IRouterPaths { direct: { pathname: `/direct/:rid${`/${string}` | ''}${`/${string}` | ''}`; pattern: '/direct/:rid/:tab?/:context?'; diff --git a/apps/meteor/lib/rooms/roomTypes/livechat.ts b/apps/meteor/lib/rooms/roomTypes/livechat.ts index 8673a4fa4570..b05cdefc07a0 100644 --- a/apps/meteor/lib/rooms/roomTypes/livechat.ts +++ b/apps/meteor/lib/rooms/roomTypes/livechat.ts @@ -2,8 +2,7 @@ import type { IRoomTypeConfig } from '../../../definition/IRoomTypeConfig'; import type { RoomCoordinator } from '../coordinator'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - export interface RouterPaths { + export interface IRouterPaths { live: { pathname: `/live/${string}${`/${string}` | ''}${`/${string}` | ''}`; pattern: '/live/:id/:tab?/:context?'; diff --git a/apps/meteor/lib/rooms/roomTypes/private.ts b/apps/meteor/lib/rooms/roomTypes/private.ts index 3aaf68b00b19..959463e94ae8 100644 --- a/apps/meteor/lib/rooms/roomTypes/private.ts +++ b/apps/meteor/lib/rooms/roomTypes/private.ts @@ -2,8 +2,7 @@ import type { IRoomTypeConfig } from '../../../definition/IRoomTypeConfig'; import type { RoomCoordinator } from '../coordinator'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - export interface RouterPaths { + export interface IRouterPaths { group: { pathname: `/group/${string}${`/${string}` | ''}${`/${string}` | ''}`; pattern: '/group/:name/:tab?/:context?'; diff --git a/apps/meteor/lib/rooms/roomTypes/public.ts b/apps/meteor/lib/rooms/roomTypes/public.ts index 9d5629853688..2f90488d8835 100644 --- a/apps/meteor/lib/rooms/roomTypes/public.ts +++ b/apps/meteor/lib/rooms/roomTypes/public.ts @@ -2,8 +2,7 @@ import type { IRoomTypeConfig } from '../../../definition/IRoomTypeConfig'; import type { RoomCoordinator } from '../coordinator'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - export interface RouterPaths { + export interface IRouterPaths { channel: { pathname: `/channel/${string}${`/${string}` | ''}${`/${string}` | ''}`; pattern: '/channel/:name/:tab?/:context?'; diff --git a/apps/meteor/lib/rooms/roomTypes/voip.ts b/apps/meteor/lib/rooms/roomTypes/voip.ts index 610d88ac06e4..04ae151ef5a4 100644 --- a/apps/meteor/lib/rooms/roomTypes/voip.ts +++ b/apps/meteor/lib/rooms/roomTypes/voip.ts @@ -2,8 +2,7 @@ import type { IRoomTypeConfig } from '../../../definition/IRoomTypeConfig'; import type { RoomCoordinator } from '../coordinator'; declare module '@rocket.chat/ui-contexts' { - // eslint-disable-next-line @typescript-eslint/naming-convention - export interface RouterPaths { + export interface IRouterPaths { voip: { pathname: `/voip/${string}${`/${string}` | ''}${`/${string}` | ''}`; pattern: '/voip/:id/:tab?/:context?'; diff --git a/apps/meteor/lib/router.ts b/apps/meteor/lib/router.ts deleted file mode 100644 index e6e0e8602660..000000000000 --- a/apps/meteor/lib/router.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { compile, match } from 'path-to-regexp'; - -type PathParams = TPath extends `${string}:${infer TParam}/${infer TRest}` - ? (TParam extends `${infer U}?` ? U : TParam) | PathParams - : TPath extends `${string}:${infer TParam}` - ? TParam extends `${infer U}?` - ? U - : TParam - : never; - -export function generatePath(path: TPath, params?: Partial, string>>): string { - return compile(path, { encode: encodeURIComponent })(params); -} - -export type Params = Readonly>; - -// eslint-disable-next-line @typescript-eslint/naming-convention -interface PathMatch { - params: Params; - pathname: string; - pattern: PathPattern; -} - -// eslint-disable-next-line @typescript-eslint/naming-convention -interface PathPattern { - path: string; - caseSensitive?: boolean; - end?: boolean; -} - -export function matchPath(pattern: PathPattern | string, pathname: string): PathMatch | null { - if (typeof pattern === 'string') { - pattern = { path: pattern, caseSensitive: false, end: true }; - } - - const result = match(pattern.path, { encode: encodeURIComponent, sensitive: pattern.caseSensitive, end: pattern.end })(pathname); - - if (!result) { - return null; - } - - return { - params: result.params as Params, - pathname: result.path, - pattern, - }; -} - -export const createSearchParams = (init?: string[][] | Record | string | URLSearchParams) => new URLSearchParams(init); diff --git a/apps/meteor/lib/utils/generatePath.ts b/apps/meteor/lib/utils/generatePath.ts new file mode 100644 index 000000000000..40c4bab1043c --- /dev/null +++ b/apps/meteor/lib/utils/generatePath.ts @@ -0,0 +1,13 @@ +import { compile } from 'path-to-regexp'; + +type PathParams = TPath extends `${string}:${infer TParam}/${infer TRest}` + ? (TParam extends `${infer U}?` ? U : TParam) | PathParams + : TPath extends `${string}:${infer TParam}` + ? TParam extends `${infer U}?` + ? U + : TParam + : never; + +export function generatePath(path: TPath, params?: Partial, string>>): string { + return compile(path, { encode: encodeURIComponent })(params); +} diff --git a/apps/meteor/tests/mocks/client/RouterContextMock.tsx b/apps/meteor/tests/mocks/client/RouterContextMock.tsx index 9c703ec51e76..a15c4bb1d51c 100644 --- a/apps/meteor/tests/mocks/client/RouterContextMock.tsx +++ b/apps/meteor/tests/mocks/client/RouterContextMock.tsx @@ -52,9 +52,10 @@ const RouterContextMock = ({ children, initialRoute, navigate, pushRoute, replac const setCurrentRoute = currentRoute.set; return { + getRoutePath: () => '/', + navigate: navigate ?? (() => undefined), queryRoutePath: () => [() => (): void => undefined, (): undefined => undefined], queryRouteUrl: () => [() => (): void => undefined, (): undefined => undefined], - navigate: navigate ?? (() => undefined), pushRoute: (name, parameters, queryStringParameters) => { const queryParams = typeof queryStringParameters === 'function' ? queryStringParameters({}) : queryStringParameters; setCurrentRoute([name, parameters, queryParams]); @@ -69,7 +70,6 @@ const RouterContextMock = ({ children, initialRoute, navigate, pushRoute, replac queryQueryStringParameter: () => [() => (): void => undefined, (): undefined => undefined], queryCurrentRoute: () => [subscribeToCurrentRoute, getCurrentRoute], setQueryString: () => undefined, - getRoutePath: () => '/', }; }, [currentRoute.get, currentRoute.set, currentRoute.subscribe, navigate, pushRoute, replaceRoute])} > diff --git a/packages/ui-contexts/src/RouterContext.ts b/packages/ui-contexts/src/RouterContext.ts index 3c0bf4c0bb3c..21cbdc8198b2 100644 --- a/packages/ui-contexts/src/RouterContext.ts +++ b/packages/ui-contexts/src/RouterContext.ts @@ -1,7 +1,6 @@ import { createContext } from 'react'; -// eslint-disable-next-line @typescript-eslint/naming-convention -interface Paths { +export interface IRouterPaths { index: { pattern: '/'; pathname: '/'; @@ -12,44 +11,25 @@ interface Paths { }; } -type Pathname = Paths[keyof Paths]['pathname']; -type Search = string; -type Hash = string; - -type Path = { - pathname: Pathname; - search: Search; - hash: Hash; -}; +export type RouterPathName = keyof IRouterPaths; +export type RouterPathPattern = IRouterPaths[keyof IRouterPaths]['pattern']; +type Pathname = IRouterPaths[keyof IRouterPaths]['pathname']; type To = | Pathname - | Partial | { - pattern: Paths[keyof Paths]['pattern']; + pattern: RouterPathPattern; params: Record; search?: Record; } | { - pathname: Paths[keyof Paths]['pathname']; + pathname: Pathname; search?: Record; }; type RelativeRoutingType = 'route' | 'path'; -export type NavigateFunction = { - ( - to: To, - options?: { - replace?: boolean; - state?: any; - relative?: RelativeRoutingType; - }, - ): void; - (delta: number): void; -}; - -export type RouteName = keyof Paths; +export type RouteName = keyof IRouterPaths; export type RouteParameters = Record; @@ -58,7 +38,18 @@ export type QueryStringParameters = Record; export type RouteGroupName = string; export type RouterContextValue = { - navigate: NavigateFunction; + getRoutePath( + pattern: TPathPattern, + parameters?: Record, + search?: Record, + ): string; + getRoutePath( + name: TRouteName, + parameters?: Record, + search?: Record, + ): string; + navigate(to: To, options?: { replace?: boolean; state?: any; relative?: RelativeRoutingType }): void; + navigate(delta: number): void; queryRoutePath: ( name: RouteName, parameters: RouteParameters | undefined, @@ -89,10 +80,12 @@ export type RouterContextValue = { ]; setQueryString(parameters: Record): void; setQueryString(fn: (parameters: Record) => Record): void; - getRoutePath(nameOrPathDef: string, parameters?: Record, queryStringParameters?: Record): string; }; export const RouterContext = createContext({ + getRoutePath: () => { + throw new Error('not implemented'); + }, navigate: () => undefined, queryRoutePath: () => [() => (): void => undefined, (): undefined => undefined], queryRouteUrl: () => [() => (): void => undefined, (): undefined => undefined], @@ -105,9 +98,4 @@ export const RouterContext = createContext({ (): [undefined, RouteParameters, QueryStringParameters, undefined] => [undefined, {}, {}, undefined], ], setQueryString: () => undefined, - getRoutePath: () => { - throw new Error('not implemented'); - }, }); - -export type { Paths as RouterPaths }; diff --git a/packages/ui-contexts/src/hooks/useLogout.ts b/packages/ui-contexts/src/hooks/useLogout.ts index 7f462eff50ba..fbbe758d48c4 100644 --- a/packages/ui-contexts/src/hooks/useLogout.ts +++ b/packages/ui-contexts/src/hooks/useLogout.ts @@ -2,15 +2,15 @@ import { useContext } from 'react'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { UserContext } from '../UserContext'; -import { useNavigate } from './useNavigate'; +import { useRouter } from './useRouter'; export const useLogout = (): (() => void) => { - const navigate = useNavigate(); + const router = useRouter(); const { logout } = useContext(UserContext); const handleLogout = useMutableCallback(() => { logout(); - navigate('/'); + router.navigate('/'); }); return handleLogout; diff --git a/packages/ui-contexts/src/hooks/useNavigate.ts b/packages/ui-contexts/src/hooks/useNavigate.ts deleted file mode 100644 index de6bd853c2ba..000000000000 --- a/packages/ui-contexts/src/hooks/useNavigate.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useContext } from 'react'; - -import { RouterContext } from '../RouterContext'; - -export const useNavigate = () => { - const { navigate } = useContext(RouterContext); - return navigate; -}; diff --git a/packages/ui-contexts/src/hooks/useRoutePath.ts b/packages/ui-contexts/src/hooks/useRoutePath.ts index f37bbd99add1..f56f0027f8fa 100644 --- a/packages/ui-contexts/src/hooks/useRoutePath.ts +++ b/packages/ui-contexts/src/hooks/useRoutePath.ts @@ -1,11 +1,11 @@ import { useContext, useMemo } from 'react'; import { useSyncExternalStore } from 'use-sync-external-store/shim'; -import type { QueryStringParameters, RouteParameters, RouterPaths } from '../RouterContext'; +import type { QueryStringParameters, RouteParameters, IRouterPaths } from '../RouterContext'; import { RouterContext } from '../RouterContext'; export const useRoutePath = ( - name: keyof RouterPaths, + name: keyof IRouterPaths, parameters?: RouteParameters, queryStringParameters?: QueryStringParameters, ): string | undefined => { diff --git a/packages/ui-contexts/src/hooks/useRouter.ts b/packages/ui-contexts/src/hooks/useRouter.ts new file mode 100644 index 000000000000..314e7682bbf8 --- /dev/null +++ b/packages/ui-contexts/src/hooks/useRouter.ts @@ -0,0 +1,5 @@ +import { useContext } from 'react'; + +import { RouterContext } from '../RouterContext'; + +export const useRouter = () => useContext(RouterContext); diff --git a/packages/ui-contexts/src/index.ts b/packages/ui-contexts/src/index.ts index 12fe66c07e15..834dfd7c28ce 100644 --- a/packages/ui-contexts/src/index.ts +++ b/packages/ui-contexts/src/index.ts @@ -5,7 +5,7 @@ export { ConnectionStatusContext, ConnectionStatusContextValue } from './Connect export { CustomSoundContext, CustomSoundContextValue } from './CustomSoundContext'; export { LayoutContext, LayoutContextValue } from './LayoutContext'; export { ModalContext, ModalContextValue } from './ModalContext'; -export { RouterContext, RouterContextValue, RouterPaths } from './RouterContext'; +export * from './RouterContext'; export { ServerContext, ServerContextValue } from './ServerContext'; export { SessionContext, SessionContextValue } from './SessionContext'; export { SettingsContext, SettingsContextValue, SettingsContextQuery } from './SettingsContext'; @@ -46,13 +46,13 @@ export { useLogout } from './hooks/useLogout'; export { useMediaUrl } from './hooks/useMediaUrl'; export { useMethod } from './hooks/useMethod'; export { useModal } from './hooks/useModal'; -export { useNavigate } from './hooks/useNavigate'; export { usePermission } from './hooks/usePermission'; export { usePermissionWithScopedRoles } from './hooks/usePermissionWithScopedRoles'; export { useQueryStringParameter } from './hooks/useQueryStringParameter'; export { useRole } from './hooks/useRole'; export { useRolesDescription } from './hooks/useRolesDescription'; export { useRoomAvatarPath } from './hooks/useRoomAvatarPath'; +export { useRouter } from './hooks/useRouter'; export { useRoute } from './hooks/useRoute'; export { useRouteParameter } from './hooks/useRouteParameter'; export { useRoutePath } from './hooks/useRoutePath'; diff --git a/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx b/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx index e14b2f7dd668..cfb6cc50c629 100644 --- a/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx +++ b/packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx @@ -1,6 +1,6 @@ import { Button, Field, Modal, Box, PasswordInput, InputBoxSkeleton } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useNavigate, useRouteParameter, useUser, useMethod, useTranslation, useLoginWithToken } from '@rocket.chat/ui-contexts'; +import { useRouter, useRouteParameter, useUser, useMethod, useTranslation, useLoginWithToken } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import { Form } from '@rocket.chat/layout'; import { useForm } from 'react-hook-form'; @@ -24,7 +24,7 @@ const ResetPasswordPage = (): ReactElement => { token: user ? undefined : token, }); - const navigate = useNavigate(); + const router = useRouter(); const changePasswordReason = getChangePasswordReason(user || {}); @@ -47,7 +47,7 @@ const ResetPasswordPage = (): ReactElement => { if (token) { const result = await resetPassword(token, data.password); await loginWithToken(result.token); - navigate('/home'); + router.navigate('/home'); } else { await setUserPassword(data.password); }