From 12e34013f8daa38f919d4aa55a6b3de76937454b Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 8 Mar 2023 18:35:51 +0000 Subject: [PATCH 1/3] refactor: default noSsr to true in useMediaQuery --- packages/web/src/components/AppBar/index.tsx | 4 +--- packages/web/src/components/ConditionalIconButton/index.tsx | 4 +--- packages/web/src/components/Drawer/index.tsx | 4 +--- packages/web/src/components/Layout/index.tsx | 4 +--- packages/web/src/components/SettingsLayout/index.tsx | 4 +--- packages/web/src/pages/Application/index.tsx | 4 +--- packages/web/src/styles/theme.ts | 5 +++++ 7 files changed, 11 insertions(+), 18 deletions(-) diff --git a/packages/web/src/components/AppBar/index.tsx b/packages/web/src/components/AppBar/index.tsx index 56d52bd3..cf32768a 100644 --- a/packages/web/src/components/AppBar/index.tsx +++ b/packages/web/src/components/AppBar/index.tsx @@ -29,9 +29,7 @@ export default function AppBar(props: AppBarProps): React.ReactElement { const { drawerOpen, onDrawerOpen, onDrawerClose, maxWidth = false } = props; const theme = useTheme(); - const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'), { - noSsr: true, - }); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md')); const [accountMenuAnchorElement, setAccountMenuAnchorElement] = React.useState(null); diff --git a/packages/web/src/components/ConditionalIconButton/index.tsx b/packages/web/src/components/ConditionalIconButton/index.tsx index 4c72a4a9..dd8bcaf4 100644 --- a/packages/web/src/components/ConditionalIconButton/index.tsx +++ b/packages/web/src/components/ConditionalIconButton/index.tsx @@ -10,9 +10,7 @@ import { IconButton } from './style'; export default function ConditionalIconButton(props: any): React.ReactElement { const { icon, ...buttonProps } = props; const theme = useTheme(); - const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'), { - noSsr: true, - }); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md')); if (matchSmallScreens) { return ( diff --git a/packages/web/src/components/Drawer/index.tsx b/packages/web/src/components/Drawer/index.tsx index 936a1853..9d677bf1 100644 --- a/packages/web/src/components/Drawer/index.tsx +++ b/packages/web/src/components/Drawer/index.tsx @@ -31,9 +31,7 @@ type DrawerProps = { export default function Drawer(props: DrawerProps): React.ReactElement { const { links = [], bottomLinks = [], ...drawerProps } = props; const theme = useTheme(); - const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'), { - noSsr: true, - }); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md')); const formatMessage = useFormatMessage(); const closeOnClick = (event: React.SyntheticEvent) => { diff --git a/packages/web/src/components/Layout/index.tsx b/packages/web/src/components/Layout/index.tsx index 05e3838c..09c738de 100644 --- a/packages/web/src/components/Layout/index.tsx +++ b/packages/web/src/components/Layout/index.tsx @@ -52,9 +52,7 @@ export default function PublicLayout({ }: PublicLayoutProps): React.ReactElement { const version = useVersion(); const theme = useTheme(); - const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg'), { - noSsr: true, - }); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg')); const [isDrawerOpen, setDrawerOpen] = React.useState(!matchSmallScreens); const openDrawer = () => setDrawerOpen(true); diff --git a/packages/web/src/components/SettingsLayout/index.tsx b/packages/web/src/components/SettingsLayout/index.tsx index 488349ea..ddeb90da 100644 --- a/packages/web/src/components/SettingsLayout/index.tsx +++ b/packages/web/src/components/SettingsLayout/index.tsx @@ -49,9 +49,7 @@ export default function SettingsLayout({ }: SettingsLayoutProps): React.ReactElement { const { isCloud } = useAutomatischInfo(); const theme = useTheme(); - const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg'), { - noSsr: true, - }); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg')); const [isDrawerOpen, setDrawerOpen] = React.useState(!matchSmallScreens); const openDrawer = () => setDrawerOpen(true); diff --git a/packages/web/src/pages/Application/index.tsx b/packages/web/src/pages/Application/index.tsx index f3db7ad9..2bee8da6 100644 --- a/packages/web/src/pages/Application/index.tsx +++ b/packages/web/src/pages/Application/index.tsx @@ -51,9 +51,7 @@ const ReconnectConnection = (props: any): React.ReactElement => { export default function Application(): React.ReactElement | null { const theme = useTheme(); - const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'), { - noSsr: true, - }); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md')); const formatMessage = useFormatMessage(); const connectionsPathMatch = useMatch({ path: URLS.APP_CONNECTIONS_PATTERN, diff --git a/packages/web/src/styles/theme.ts b/packages/web/src/styles/theme.ts index 4624bb5b..11a8fe7c 100644 --- a/packages/web/src/styles/theme.ts +++ b/packages/web/src/styles/theme.ts @@ -251,6 +251,11 @@ const extendedTheme = createTheme({ }), }, }, + MuiUseMediaQuery: { + defaultProps: { + noSsr: true, + }, + }, MuiTab: { styleOverrides: { root: ({ theme }) => ({ From 1669708041c1fa5ca6ed6135135e62f00ca73091 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 8 Mar 2023 18:37:32 +0000 Subject: [PATCH 2/3] feat: show usage alert as of threshold --- packages/web/src/components/AppBar/index.tsx | 3 + .../src/components/UsageAlert/index.ee.tsx | 57 +++++++++++++++++++ packages/web/src/config/app.ts | 1 + packages/web/src/hooks/useUsageAlert.ee.ts | 46 +++++++++++++++ packages/web/src/locales/en.json | 6 +- 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 packages/web/src/components/UsageAlert/index.ee.tsx create mode 100644 packages/web/src/hooks/useUsageAlert.ee.ts diff --git a/packages/web/src/components/AppBar/index.tsx b/packages/web/src/components/AppBar/index.tsx index cf32768a..dfb4f4d1 100644 --- a/packages/web/src/components/AppBar/index.tsx +++ b/packages/web/src/components/AppBar/index.tsx @@ -12,6 +12,7 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import * as URLS from 'config/urls'; import AccountDropdownMenu from 'components/AccountDropdownMenu'; +import UsageAlert from 'components/UsageAlert/index.ee'; import Container from 'components/Container'; import { FormattedMessage } from 'react-intl'; import { Link } from './style'; @@ -81,6 +82,8 @@ export default function AppBar(props: AppBarProps): React.ReactElement { + + ( + (props, ref) => , +); + +export default function UsageAlert() { + const formatMessage = useFormatMessage(); + const usageAlert = useUsageAlert(); + + if (!usageAlert.showAlert) return (); + + return ( + + + + + {usageAlert.alertMessage} + + + + + + + + + ); +} diff --git a/packages/web/src/config/app.ts b/packages/web/src/config/app.ts index 184dbe2b..ea01596c 100644 --- a/packages/web/src/config/app.ts +++ b/packages/web/src/config/app.ts @@ -7,6 +7,7 @@ const config: Config = { graphqlUrl: process.env.REACT_APP_GRAPHQL_URL as string, notificationsUrl: process.env.REACT_APP_NOTIFICATIONS_URL as string, chatwootBaseUrl: 'https://app.chatwoot.com', + supportEmailAddress: 'support@automatisch.io' }; export default config; diff --git a/packages/web/src/hooks/useUsageAlert.ee.ts b/packages/web/src/hooks/useUsageAlert.ee.ts new file mode 100644 index 00000000..2bfd802a --- /dev/null +++ b/packages/web/src/hooks/useUsageAlert.ee.ts @@ -0,0 +1,46 @@ +import useFormatMessage from './useFormatMessage'; +import useUsageData from './useUsageData.ee'; +import usePaymentPortalUrl from './usePaymentPortalUrl.ee'; + +type UseUsageAlertReturn = { + showAlert: boolean; + hasExceededLimit?: boolean; + alertMessage?: string; + url?: string; + consumptionPercentage?: number; +}; + +export default function useUsageAlert(): UseUsageAlertReturn { + const { url, loading: paymentPortalUrlLoading } = usePaymentPortalUrl(); + const { + allowedTaskCount, + consumedTaskCount, + nextResetAt, + loading: usageDataLoading + } = useUsageData(); + const formatMessage = useFormatMessage(); + + if (paymentPortalUrlLoading || usageDataLoading) { + return { showAlert: false }; + } + + const hasLoaded = !paymentPortalUrlLoading || usageDataLoading; + const withinUsageThreshold = consumedTaskCount > allowedTaskCount * 0.7; + const consumptionPercentage = consumedTaskCount / allowedTaskCount * 100; + const showAlert = hasLoaded && withinUsageThreshold; + const hasExceededLimit = consumedTaskCount >= allowedTaskCount; + + const alertMessage = formatMessage('usageAlert.informationText', { + allowedTaskCount, + consumedTaskCount, + relativeResetDate: nextResetAt?.toRelative(), + }); + + return { + showAlert, + hasExceededLimit, + alertMessage, + consumptionPercentage, + url, + }; +} diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index ddfda549..dee7e9cd 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -136,5 +136,7 @@ "resetPasswordForm.submit": "Reset password", "resetPasswordForm.passwordFieldLabel": "Password", "resetPasswordForm.confirmPasswordFieldLabel": "Confirm password", - "resetPasswordForm.passwordUpdated": "The password has been updated. Now, you can login." -} + "resetPasswordForm.passwordUpdated": "The password has been updated. Now, you can login.", + "usageAlert.informationText": "Tasks: {consumedTaskCount}/{allowedTaskCount} (Resets {relativeResetDate})", + "usageAlert.viewPlans": "View plans" +} \ No newline at end of file From e67adf87b281811511b1cfd9f64d62f15902588b Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Wed, 8 Mar 2023 18:37:42 +0000 Subject: [PATCH 3/3] fix: hide chatwoot in small screens --- .../src/components/LiveChat/Chatwoot.ee.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/web/src/components/LiveChat/Chatwoot.ee.tsx b/packages/web/src/components/LiveChat/Chatwoot.ee.tsx index a45f7f3e..67182189 100644 --- a/packages/web/src/components/LiveChat/Chatwoot.ee.tsx +++ b/packages/web/src/components/LiveChat/Chatwoot.ee.tsx @@ -1,4 +1,6 @@ import * as React from 'react'; +import { useTheme } from '@mui/material/styles'; +import useMediaQuery from '@mui/material/useMediaQuery'; import appConfig from 'config/app'; import useCurrentUser from 'hooks/useCurrentUser'; @@ -8,7 +10,9 @@ type ChatwootProps = { } const Chatwoot = ({ ready }: ChatwootProps) => { + const theme = useTheme(); const currentUser = useCurrentUser(); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md')); React.useEffect(function initiateChatwoot() { window.chatwootSDK.run({ @@ -30,8 +34,18 @@ const Chatwoot = ({ ready }: ChatwootProps) => { name: currentUser.fullName, }); - window.$chatwoot.toggleBubbleVisibility("show"); - }, [currentUser, ready]); + if (!matchSmallScreens) { + window.$chatwoot.toggleBubbleVisibility("show"); + } + }, [currentUser, ready, matchSmallScreens]); + + React.useLayoutEffect(function hideChatwoot() { + if (matchSmallScreens) { + window.$chatwoot?.toggleBubbleVisibility('hide'); + } else { + window.$chatwoot?.toggleBubbleVisibility('show'); + } + }, [matchSmallScreens]) return (