diff --git a/apps/web/.env.example b/apps/web/.env.example index 424cd658..dd87b26d 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -102,5 +102,8 @@ NEXT_PUBLIC_INTERCOM_APP_ID= # Zendesk Config NEXT_PUBLIC_ZENDESK_KEY= +# Help Scout Config +NEXT_PUBLIC_HELPSCOUT_KEY= + # Set it to "1" if you need to run E2E tests locally NEXT_PUBLIC_IS_E2E= diff --git a/apps/web/components/Shell.tsx b/apps/web/components/Shell.tsx index 548f57c7..6feb6a50 100644 --- a/apps/web/components/Shell.tsx +++ b/apps/web/components/Shell.tsx @@ -26,8 +26,7 @@ import Dropdown, { } from "@calcom/ui/Dropdown"; import LicenseBanner from "@ee/components/LicenseBanner"; import TrialBanner from "@ee/components/TrialBanner"; -import IntercomMenuItem from "@ee/lib/intercom/IntercomMenuItem"; -import ZendeskMenuItem from "@ee/lib/zendesk/ZendeskMenuItem"; +import HelpMenuItem from "@ee/components/support/HelpMenuItem"; import classNames from "@lib/classNames"; import { NEXT_PUBLIC_BASE_URL } from "@lib/config/constants"; @@ -490,8 +489,9 @@ function UserDropdown({ small }: { small?: boolean }) { {t("visit_roadmap")} - - + + + + + + + + ); +} diff --git a/apps/web/ee/lib/helpscout/HelpscoutMenuItem.tsx b/apps/web/ee/lib/helpscout/HelpscoutMenuItem.tsx new file mode 100644 index 00000000..f41c251e --- /dev/null +++ b/apps/web/ee/lib/helpscout/HelpscoutMenuItem.tsx @@ -0,0 +1,42 @@ +import { ChatAltIcon } from "@heroicons/react/solid"; +import { useState } from "react"; +import { HelpScout, useChat } from "react-live-chat-loader"; + +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { DropdownMenuItem } from "@calcom/ui/Dropdown"; + +import classNames from "@lib/classNames"; + +export default function HelpscoutMenuItem() { + const { t } = useLocale(); + const [active, setActive] = useState(false); + + const [state, loadChat] = useChat(); + + function handleClick() { + setActive(true); + loadChat({ open: true }); + } + + if (!process.env.NEXT_PUBLIC_HELPSCOUT_KEY) return null; + else + return ( + <> + + + + {active && } + + ); +} diff --git a/apps/web/ee/lib/helpscout/provider.tsx b/apps/web/ee/lib/helpscout/provider.tsx new file mode 100644 index 00000000..fcd50416 --- /dev/null +++ b/apps/web/ee/lib/helpscout/provider.tsx @@ -0,0 +1,10 @@ +import { FC } from "react"; +import { LiveChatLoaderProvider } from "react-live-chat-loader"; + +const Provider: FC = ({ children }) => ( + + <>{children} + +); + +export default Provider; diff --git a/apps/web/ee/lib/helpscout/providerDynamic.tsx b/apps/web/ee/lib/helpscout/providerDynamic.tsx new file mode 100644 index 00000000..1849904a --- /dev/null +++ b/apps/web/ee/lib/helpscout/providerDynamic.tsx @@ -0,0 +1,8 @@ +import dynamic from "next/dynamic"; +import { Fragment } from "react"; + +const DynamicHelpscoutProvider = process.env.NEXT_PUBLIC_HELPSCOUT_KEY + ? dynamic(() => import("./provider")) + : Fragment; + +export default DynamicHelpscoutProvider; diff --git a/apps/web/ee/lib/zendesk/ZendeskMenuItem.tsx b/apps/web/ee/lib/zendesk/ZendeskMenuItem.tsx index bc2bb6b4..5fc66132 100644 --- a/apps/web/ee/lib/zendesk/ZendeskMenuItem.tsx +++ b/apps/web/ee/lib/zendesk/ZendeskMenuItem.tsx @@ -2,10 +2,10 @@ import { ChatAltIcon } from "@heroicons/react/solid"; import Script from "next/script"; import { useState } from "react"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; import { DropdownMenuItem } from "@calcom/ui/Dropdown"; import classNames from "@lib/classNames"; -import { useLocale } from "@lib/hooks/useLocale"; const ZENDESK_KEY = process.env.NEXT_PUBLIC_ZENDESK_KEY; diff --git a/apps/web/lib/app-providers.tsx b/apps/web/lib/app-providers.tsx index c8381599..2d96b261 100644 --- a/apps/web/lib/app-providers.tsx +++ b/apps/web/lib/app-providers.tsx @@ -3,7 +3,10 @@ import { SessionProvider } from "next-auth/react"; import { appWithTranslation } from "next-i18next"; import type { AppProps as NextAppProps } from "next/app"; import React, { ComponentProps, ReactNode } from "react"; +import { LiveChatLoaderProvider } from "react-live-chat-loader"; +import { HelpScout } from "react-live-chat-loader"; +import DynamicHelpscoutProvider from "@ee/lib/helpscout/providerDynamic"; import DynamicIntercomProvider from "@ee/lib/intercom/providerDynamic"; import usePublicPage from "@lib/hooks/usePublicPage"; @@ -55,7 +58,9 @@ const AppProviders = (props: AppPropsWithChildren) => { {isPublicPage ? ( RemainingProviders ) : ( - {RemainingProviders} + + {RemainingProviders} + )} diff --git a/apps/web/package.json b/apps/web/package.json index 277784f6..6a654176 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -87,6 +87,7 @@ "react-hook-form": "^7.20.4", "react-hot-toast": "^2.1.0", "react-intl": "^5.22.0", + "react-live-chat-loader": "^2.7.3", "react-multi-email": "^0.5.3", "react-phone-number-input": "^3.1.41", "react-query": "^3.33.7", diff --git a/apps/web/styles/globals.css b/apps/web/styles/globals.css index 840d3a2c..f976a14b 100644 --- a/apps/web/styles/globals.css +++ b/apps/web/styles/globals.css @@ -165,12 +165,23 @@ button[role="switch"][data-state="checked"] span { /* hide chat bubble on mobile */ @media only screen and (max-width: 768px) { + /* Intercom FAB*/ #launcher { display: none !important; } + + /* Zendesk FAB*/ div[role="presentation"] > iframe { display: none !important; } + + /* Helpscout FAB*/ + .BeaconFabButtonFrame { + margin-left: -30px; + left: 50%; + bottom: 28px !important; + z-index: 1058 !important; + } } /* add padding bottom to bottom nav on standalone mode */ diff --git a/apps/website b/apps/website index 0c5841db..e54a7cc0 160000 --- a/apps/website +++ b/apps/website @@ -1 +1 @@ -Subproject commit 0c5841db96243e93ffda5cc6c26a1ea89b4bd1e3 +Subproject commit e54a7cc0ecbb36a5a6838f77d8c19ec008c8849a