diff --git a/apps/meteor/client/views/room/MessageList/MessageListErrorBoundary.tsx b/apps/meteor/client/views/room/MessageList/MessageListErrorBoundary.tsx index 62f9ddafb12..a312fe5a221 100644 --- a/apps/meteor/client/views/room/MessageList/MessageListErrorBoundary.tsx +++ b/apps/meteor/client/views/room/MessageList/MessageListErrorBoundary.tsx @@ -1,7 +1,7 @@ import { States, StatesIcon, StatesTitle, StatesSubtitle, StatesActions, StatesAction, Icon } from '@rocket.chat/fuselage'; -import { ErrorBoundary } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement, ReactNode } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; const MessageListErrorBoundary = ({ children }: { children: ReactNode }): ReactElement => { const t = useTranslation(); diff --git a/apps/meteor/client/views/room/Room/Room.tsx b/apps/meteor/client/views/room/Room/Room.tsx index 141fec6beea..82bfaa845d1 100644 --- a/apps/meteor/client/views/room/Room/Room.tsx +++ b/apps/meteor/client/views/room/Room/Room.tsx @@ -1,7 +1,7 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { ErrorBoundary } from '@rocket.chat/ui-client'; import { useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo, ReactElement } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useEmbeddedLayout } from '../../../hooks/useEmbeddedLayout'; import Announcement from '../Announcement'; @@ -43,7 +43,7 @@ export const Room = (): ReactElement => { {tab && ( - + {typeof tab.template === 'string' && ( @@ -58,7 +58,7 @@ export const Room = (): ReactElement => { {appsContextualBarContext && ( - + ( + + + {title && {title}} + + + + {children} + + + + + +); + +export default EngagementDashboardCard; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardErrorBoundary.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardErrorBoundary.tsx new file mode 100644 index 00000000000..80236e1487f --- /dev/null +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardErrorBoundary.tsx @@ -0,0 +1,45 @@ +import { States, StatesAction, StatesActions, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import { QueryErrorResetBoundary } from '@tanstack/react-query'; +import React, { ReactElement, ReactNode, useState } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; + +export type EngagementDashboardCardErrorBoundaryProps = { + children?: ReactNode; +}; + +const EngagementDashboardCardErrorBoundary = ({ children }: EngagementDashboardCardErrorBoundaryProps): ReactElement => { + const t = useTranslation(); + + const [error, setError] = useState(); + const isError = (error: unknown): error is Error => error instanceof Error; + + const errorHandler = (error: Error, info: { componentStack: string }): void => { + setError(error); + console.error('Uncaught Error:', error, info); + }; + + return ( + + {({ reset }): ReactElement => ( + ( + + + {t('Something_Went_Wrong')} + {isError(error) && error?.message} + + resetErrorBoundary()}>{t('Retry')} + + + )} + /> + )} + + ); +}; + +export default EngagementDashboardCardErrorBoundary; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardFilter.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardFilter.tsx new file mode 100644 index 00000000000..55a702b6671 --- /dev/null +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardFilter.tsx @@ -0,0 +1,14 @@ +import { Box, Flex, InputBox } from '@rocket.chat/fuselage'; +import React, { ReactElement, ReactNode } from 'react'; + +type EngagementDashboardCardFilterProps = { + children?: ReactNode; +}; + +const EngagementDashboardCardFilter = ({ children = }: EngagementDashboardCardFilterProps): ReactElement => ( + + {children && {children}} + +); + +export default EngagementDashboardCardFilter; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx index 437ba1e1baf..fd25ccb1cea 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx @@ -32,18 +32,18 @@ const EngagementDashboardPage = ({ tab = 'users', onSelectTab }: EngagementDashb ); return ( - + + - + ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/NewUsersSection.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/users/NewUsersSection.tsx index 17197cad329..e95bdd02bbb 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/NewUsersSection.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/NewUsersSection.tsx @@ -8,7 +8,7 @@ import React, { ReactElement, useMemo } from 'react'; import CounterSet from '../../../../../../client/components/dataView/CounterSet'; import { useFormatDate } from '../../../../../../client/hooks/useFormatDate'; -import Section from '../Section'; +import EngagementDashboardCardFilter from '../EngagementDashboardCardFilter'; import DownloadDataButton from '../dataView/DownloadDataButton'; import PeriodSelector from '../dataView/PeriodSelector'; import { usePeriodLabel } from '../dataView/usePeriodLabel'; @@ -78,20 +78,16 @@ const NewUsersSection = ({ timezone }: NewUsersSectionProps): ReactElement => { }, [data, utc]); return ( -
- - values?.map(({ date, newUsers }) => [date, newUsers])} - /> - - } - > + <> + + + values?.map(({ date, newUsers }) => [date, newUsers])} + /> + { )} -
+ ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx index 2b255feaecc..112ddf09c47 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx @@ -5,7 +5,7 @@ import { useTranslation } from '@rocket.chat/ui-contexts'; import moment from 'moment'; import React, { ReactElement, useMemo } from 'react'; -import Section from '../Section'; +import EngagementDashboardCardFilter from '../EngagementDashboardCardFilter'; import DownloadDataButton from '../dataView/DownloadDataButton'; import PeriodSelector from '../dataView/PeriodSelector'; import { usePeriodSelectorState } from '../dataView/usePeriodSelectorState'; @@ -75,28 +75,25 @@ const UsersByTimeOfTheDaySection = ({ timezone }: UsersByTimeOfTheDaySectionProp }, [data, utc]); return ( -
- - - data?.week - ?.map(({ users, hour, day, month, year }) => ({ - date: moment([year, month - 1, day, hour, 0, 0, 0]), - users, - })) - ?.sort((a, b) => a.date.diff(b.date)) - ?.map(({ date, users }) => [date.toISOString(), users]) - } - /> - - } - > + <> + + + + data?.week + ?.map(({ users, hour, day, month, year }) => ({ + date: moment([year, month - 1, day, hour, 0, 0, 0]), + users, + })) + ?.sort((a, b) => a.date.diff(b.date)) + ?.map(({ date, users }) => [date.toISOString(), users]) + } + /> + + {values ? ( @@ -187,7 +184,7 @@ const UsersByTimeOfTheDaySection = ({ timezone }: UsersByTimeOfTheDaySectionProp ) : ( )} -
+ ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.tsx index f870c4fa359..831cec62bee 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.tsx @@ -1,7 +1,9 @@ -import { Box, Divider, Flex, Margins } from '@rocket.chat/fuselage'; +import { Box, Flex } from '@rocket.chat/fuselage'; import { useBreakpoints } from '@rocket.chat/fuselage-hooks'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement } from 'react'; +import EngagementDashboardCard from '../EngagementDashboardCard'; import ActiveUsersSection from './ActiveUsersSection'; import BusiestChatTimesSection from './BusiestChatTimesSection'; import NewUsersSection from './NewUsersSection'; @@ -12,23 +14,29 @@ type UsersTabProps = { }; const UsersTab = ({ timezone }: UsersTabProps): ReactElement => { + const t = useTranslation(); + const isXxlScreen = useBreakpoints().includes('xxl'); return ( <> - - - - - - - + + + + + + + + + - - + + + + - - + + ); diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useActiveUsers.ts b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useActiveUsers.ts index 04db2798d16..2e3381f2e08 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useActiveUsers.ts +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useActiveUsers.ts @@ -30,6 +30,7 @@ export const useActiveUsers = ({ utc }: UseActiveUsersOptions) => { }, { refetchInterval: 5 * 60 * 1000, + useErrorBoundary: true, }, ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useHourlyChatActivity.ts b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useHourlyChatActivity.ts index 9513c9f59f2..56dd4b883c8 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useHourlyChatActivity.ts +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useHourlyChatActivity.ts @@ -29,6 +29,7 @@ export const useHourlyChatActivity = ({ displacement, utc }: UseHourlyChatActivi }, { refetchInterval: 5 * 60 * 1000, + useErrorBoundary: true, }, ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useNewUsers.ts b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useNewUsers.ts index 6be8b2b5805..2ce2c0938d2 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useNewUsers.ts +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useNewUsers.ts @@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query'; import { getPeriodRange, Period } from '../dataView/periods'; -type UseNewUsersOptions = { period: Period['key']; utc: boolean }; +export type UseNewUsersOptions = { period: Period['key']; utc: boolean }; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export const useNewUsers = ({ period, utc }: UseNewUsersOptions) => { @@ -29,6 +29,7 @@ export const useNewUsers = ({ period, utc }: UseNewUsersOptions) => { }, { refetchInterval: 5 * 60 * 1000, + useErrorBoundary: true, }, ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useUsersByTimeOfTheDay.ts b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useUsersByTimeOfTheDay.ts index c842cf97c88..93762752825 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useUsersByTimeOfTheDay.ts +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useUsersByTimeOfTheDay.ts @@ -29,6 +29,7 @@ export const useUsersByTimeOfTheDay = ({ period, utc }: UseUsersByTimeOfTheDayOp }, { refetchInterval: 5 * 60 * 1000, + useErrorBoundary: true, }, ); }; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useWeeklyChatActivity.ts b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useWeeklyChatActivity.ts index 3d5dd31d021..a04e9d5da63 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/useWeeklyChatActivity.ts +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/useWeeklyChatActivity.ts @@ -29,6 +29,7 @@ export const useWeeklyChatActivity = ({ displacement, utc }: UseWeeklyChatActivi }, { refetchInterval: 5 * 60 * 1000, + useErrorBoundary: true, }, ); }; diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 292edefb7da..9f46223a184 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -342,6 +342,7 @@ "rc-scrollbars": "^1.1.5", "react": "~17.0.2", "react-dom": "~17.0.2", + "react-error-boundary": "^3.1.4", "react-hook-form": "^7.30.0", "react-i18next": "^11.16.7", "react-keyed-flatten-children": "^1.3.0", diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index d294330e9e8..4e063a043d5 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -73,6 +73,7 @@ "react": "~17.0.2" }, "dependencies": { - "highlight.js": "^11.5.1" + "highlight.js": "^11.5.1", + "react-error-boundary": "^3.1.4" } } diff --git a/packages/gazzodown/src/katex/KatexErrorBoundary.tsx b/packages/gazzodown/src/katex/KatexErrorBoundary.tsx index 8201c258348..ba735a35b4f 100644 --- a/packages/gazzodown/src/katex/KatexErrorBoundary.tsx +++ b/packages/gazzodown/src/katex/KatexErrorBoundary.tsx @@ -1,7 +1,7 @@ import colors from '@rocket.chat/fuselage-tokens/colors.json'; import styled from '@rocket.chat/styled'; -import { ErrorBoundary } from '@rocket.chat/ui-client'; import { PropsWithChildren, ReactElement, useState } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; type KatexErrorBoundaryProps = PropsWithChildren<{ code: string }>; diff --git a/packages/ui-client/src/components/ErrorBoundary.tsx b/packages/ui-client/src/components/ErrorBoundary.tsx deleted file mode 100644 index 9e09c02cf0d..00000000000 --- a/packages/ui-client/src/components/ErrorBoundary.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, ReactNode, ErrorInfo } from 'react'; - -export class ErrorBoundary extends Component< - { fallback?: ReactNode; onError?: (error: Error, errorInfo: ErrorInfo) => void }, - { hasError: boolean } -> { - state = { hasError: false }; - - static getDerivedStateFromError(): { hasError: boolean } { - return { hasError: true }; - } - - componentDidCatch(error: Error, errorInfo: ErrorInfo): void { - this.props.onError?.(error, errorInfo); - console.error('Uncaught Error:', error, errorInfo); - } - - render(): ReactNode { - if (this.state.hasError) { - return this.props.fallback || null; - } - - return this.props.children; - } -} diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index b5f98691781..73e9adbbf71 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -1,4 +1,3 @@ export * from './ExternalLink'; -export * from './ErrorBoundary'; export * from './DotLeader'; export * from './TooltipComponent'; diff --git a/yarn.lock b/yarn.lock index ddc2822e157..c881be3aeaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4076,6 +4076,7 @@ __metadata: katex: ~0.16.0 outdent: ^0.8.0 react-dom: ~17.0.2 + react-error-boundary: ^3.1.4 ts-jest: ^27.1.4 typescript: ~4.5.5 peerDependencies: @@ -4496,6 +4497,7 @@ __metadata: rc-scrollbars: ^1.1.5 react: ~17.0.2 react-dom: ~17.0.2 + react-error-boundary: ^3.1.4 react-hook-form: ^7.30.0 react-i18next: ^11.16.7 react-keyed-flatten-children: ^1.3.0 @@ -26204,7 +26206,7 @@ __metadata: languageName: node linkType: hard -"react-error-boundary@npm:^3.1.0": +"react-error-boundary@npm:^3.1.4": version: 3.1.4 resolution: "react-error-boundary@npm:3.1.4" dependencies: