diff --git a/apps/app/components/workspace/help-section.tsx b/apps/app/components/workspace/help-section.tsx index c315ae31b..e0d1531ee 100644 --- a/apps/app/components/workspace/help-section.tsx +++ b/apps/app/components/workspace/help-section.tsx @@ -1,8 +1,14 @@ import { useState, useRef, FC } from "react"; -import { Transition } from "@headlessui/react"; + import Link from "next/link"; + +// headless ui +import { Transition } from "@headlessui/react"; +// hooks +import useTheme from "hooks/use-theme"; +import useOutsideClickDetector from "hooks/use-outside-click-detector"; // icons -import { ArrowLongLeftIcon, InboxIcon } from "@heroicons/react/24/outline"; +import { ArrowLongLeftIcon, ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline"; import { QuestionMarkCircleIcon, BoltIcon, @@ -10,9 +16,6 @@ import { DiscordIcon, GithubIcon, } from "components/icons"; -// hooks -import useTheme from "hooks/use-theme"; -import useOutsideClickDetector from "hooks/use-outside-click-detector"; const helpOptions = [ { @@ -31,9 +34,10 @@ const helpOptions = [ Icon: GithubIcon, }, { - name: "Email us", - href: "mailto:hello@plane.so", - Icon: InboxIcon, + name: "Chat with us", + href: null, + onClick: () => (window as any).$crisp.push(["do", "chat:show"]), + Icon: ChatBubbleOvalLeftEllipsisIcon, }, ]; @@ -119,20 +123,35 @@ export const WorkspaceHelpSection: FC = (props) => { leaveTo="transform opacity-0 scale-95" >
- {helpOptions.map(({ name, Icon, href }) => ( - - - - {name} - - - ))} + {helpOptions.map(({ name, Icon, href, onClick }) => { + if (href) + return ( + + + + {name} + + + ); + else + return ( + + ); + })}
diff --git a/apps/app/constants/crisp.tsx b/apps/app/constants/crisp.tsx new file mode 100644 index 000000000..8c50893dc --- /dev/null +++ b/apps/app/constants/crisp.tsx @@ -0,0 +1,44 @@ +import useUser from "hooks/use-user"; +import { useCallback, useEffect } from "react"; + +declare global { + interface Window { + $crisp: any; + CRISP_WEBSITE_ID: any; + } +} + +const Crisp = () => { + const { user } = useUser(); + + const validateCurrentUser = useCallback(() => { + const currentUser = user ? user : null; + + if (currentUser && currentUser.email) return currentUser.email; + + return null; + }, [user]); + + useEffect(() => { + if (typeof window && validateCurrentUser()) { + window.$crisp = []; + window.CRISP_WEBSITE_ID = process.env.NEXT_PUBLIC_CRISP_ID; + (function () { + var d = document; + var s = d.createElement("script"); + s.src = "https://client.crisp.chat/l.js"; + s.async = true; + d.getElementsByTagName("head")[0].appendChild(s); + // defining email when logged in + if (validateCurrentUser()) { + window.$crisp.push(["set", "user:email", [validateCurrentUser()]]); + window.$crisp.push(["do", "chat:hide"]); + window.$crisp.push(["do", "chat:close"]); + } + })(); + } + }, [validateCurrentUser]); + + return <>; +}; +export default Crisp; diff --git a/apps/app/pages/_app.tsx b/apps/app/pages/_app.tsx index 23eb82e50..617913e98 100644 --- a/apps/app/pages/_app.tsx +++ b/apps/app/pages/_app.tsx @@ -1,3 +1,5 @@ +import dynamic from "next/dynamic"; + // styles import "styles/globals.css"; import "styles/editor.css"; @@ -16,6 +18,8 @@ import { ThemeContextProvider } from "contexts/theme.context"; // types import type { AppProps } from "next/app"; +const CrispWithNoSSR = dynamic(() => import("constants/crisp"), { ssr: false }); + // nprogress NProgress.configure({ showSpinner: false }); Router.events.on("routeChangeStart", NProgress.start); @@ -27,6 +31,7 @@ function MyApp({ Component, pageProps }: AppProps) { + diff --git a/turbo.json b/turbo.json index 4b033cd68..7077fbe1e 100644 --- a/turbo.json +++ b/turbo.json @@ -13,7 +13,8 @@ "NEXT_PUBLIC_GITHUB_APP_NAME", "NEXT_PUBLIC_ENABLE_SENTRY", "NEXT_PUBLIC_ENABLE_OAUTH", - "NEXT_PUBLIC_UNSPLASH_ACCESS" + "NEXT_PUBLIC_UNSPLASH_ACCESS", + "NEXT_PUBLIC_CRISP_ID" ], "pipeline": { "build": {