feat: always show intercom on desktop by default (hidden on mobile) (#14423)

* feat: always show intercom on desktop by default (hidden on mobile)

* Revert "feat: always show intercom on desktop by default (hidden on mobile)"

This reverts commit d14a7b0808a5c3b7f15de75d3a422c4ec5e14f2b.

* feat: always show intercom on desktop by default (hidden on mobile)

* fix: type error

* refactor

* saved showIntercom in localstorage instead of DB

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
Somay Chauhan
2024-04-11 18:58:37 +00:00
committed by GitHub
co-authored by Peer Richelsen
parent 0c67f4940a
commit f010279303
7 changed files with 106 additions and 64 deletions
@@ -9,7 +9,6 @@ import { memo, useEffect, useState } from "react";
import { z } from "zod";
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
import useIntercom from "@calcom/features/ee/support/lib/intercom/useIntercom";
import { EventTypeEmbedButton, EventTypeEmbedDialog } from "@calcom/features/embed/EventTypeEmbed";
import { EventTypeDescription } from "@calcom/features/eventtypes/components";
import CreateEventTypeDialog from "@calcom/features/eventtypes/components/CreateEventTypeDialog";
@@ -950,8 +949,6 @@ const EventTypesPage: React.FC & {
getLayout?: AppProps["Component"]["getLayout"];
} = () => {
const { t } = useLocale();
const searchParams = useCompatSearchParams();
const { open } = useIntercom();
const { data: user } = useMeQuery();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [showProfileBanner, setShowProfileBanner] = useState(false);
@@ -966,13 +963,6 @@ const EventTypesPage: React.FC & {
staleTime: 1 * 60 * 60 * 1000,
});
useEffect(() => {
if (searchParams?.get("openIntercom") === "true") {
open();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
setShowProfileBanner(
!!orgBranding && !document.cookie.includes("calcom-profile-banner=1") && !user?.completedOnboarding
@@ -2403,5 +2403,7 @@
"unreviewed": "Unreviewed",
"rating_url_info":"The URL for Rating Feedback Form",
"no_show_url_info":"The URL for No Show Feedback",
"no_support_needed":"No Support Needed?",
"hide_support":"Hide Support",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -5,7 +5,6 @@ import { Icon, UpgradeTeamsBadge } from "@calcom/ui";
import FreshChatMenuItem from "../lib/freshchat/FreshChatMenuItem";
import HelpscoutMenuItem from "../lib/helpscout/HelpscoutMenuItem";
import IntercomMenuItem from "../lib/intercom/IntercomMenuItem";
import ZendeskMenuItem from "../lib/zendesk/ZendeskMenuItem";
interface ContactMenuItem {
@@ -20,7 +19,6 @@ export default function ContactMenuItem(props: ContactMenuItem) {
<>
{hasPaidPlan ? (
<>
<IntercomMenuItem onHelpItemSelect={onHelpItemSelect} />
<ZendeskMenuItem onHelpItemSelect={onHelpItemSelect} />
<HelpscoutMenuItem onHelpItemSelect={onHelpItemSelect} />
<FreshChatMenuItem onHelpItemSelect={onHelpItemSelect} />
@@ -2,9 +2,8 @@ import { useState } from "react";
import { useChat } from "react-live-chat-loader";
import classNames from "@calcom/lib/classNames";
import { JOIN_DISCORD } from "@calcom/lib/constants";
import { useHasPaidPlan } from "@calcom/lib/hooks/useHasPaidPlan";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { localStorage } from "@calcom/lib/webstorage";
import { trpc } from "@calcom/trpc/react";
import { Button, showToast, TextArea } from "@calcom/ui";
import { Icon } from "@calcom/ui";
@@ -20,13 +19,21 @@ interface HelpMenuItemProps {
export default function HelpMenuItem({ onHelpItemSelect }: HelpMenuItemProps) {
const [rating, setRating] = useState<null | string>(null);
const { open } = useIntercom();
const [showIntercom, setShowIntercom] = useState<boolean>(
localStorage.getItem("showIntercom") === "false" ? false : true
);
const { open, shutdown } = useIntercom();
const [comment, setComment] = useState("");
const [disableSubmit, setDisableSubmit] = useState(true);
const [active, setActive] = useState(false);
const [, loadChat] = useChat();
const { t } = useLocale();
const toggleIntercom = (value: boolean) => {
setShowIntercom(value);
localStorage.setItem("showIntercom", String(value));
};
const { setActive: setFreshChat } = useFreshChat();
const mutation = trpc.viewer.submitFeedback.useMutation({
@@ -46,8 +53,6 @@ export default function HelpMenuItem({ onHelpItemSelect }: HelpMenuItemProps) {
mutation.mutate({ rating: rating, comment: comment });
};
const { hasPaidPlan } = useHasPaidPlan();
return (
<div className="bg-default border-default w-full rounded-md">
<div className="w-full py-5">
@@ -71,7 +76,6 @@ export default function HelpMenuItem({ onHelpItemSelect }: HelpMenuItemProps) {
<ContactMenuItem onHelpItemSelect={onHelpItemSelect} />
</div>
</div>
<hr className="border-muted" />
<div className="w-full p-5">
<p className="text-subtle mb-1">{t("feedback").toUpperCase()}</p>
@@ -188,13 +192,21 @@ export default function HelpMenuItem({ onHelpItemSelect }: HelpMenuItemProps) {
</div>
)}
</div>
<div className="text-subtle bg-muted w-full p-5">
<p className="">{t("specific_issue")}</p>
{hasPaidPlan ? (
<button
className="hover:text-emphasis text-defualt font-medium underline"
onClick={async () => {
setActive(true);
{/* visible on desktop */}
<div className="text-subtle bg-muted hidden w-full flex-col p-5 md:block">
<p className="">{showIntercom ? t("no_support_needed") : t("specific_issue")}</p>
<button
className="hover:text-emphasis text-defualt font-medium underline"
onClick={async () => {
setActive(true);
if (showIntercom) {
if (isFreshChatEnabled) {
setFreshChat(false);
} else if (isInterComEnabled) {
shutdown();
}
toggleIntercom(false);
} else {
if (isFreshChatEnabled) {
setFreshChat(true);
} else if (isInterComEnabled) {
@@ -202,19 +214,42 @@ export default function HelpMenuItem({ onHelpItemSelect }: HelpMenuItemProps) {
} else {
loadChat({ open: true });
}
toggleIntercom(true);
}
onHelpItemSelect();
}}>
{showIntercom ? t("hide_support") : t("contact_support")}
</button>
<span> {t("or").toLowerCase()} </span>
<a
onClick={() => onHelpItemSelect()}
className="hover:text-emphasis text-defualt font-medium underline"
href="https://cal.com/docs"
target="_blank"
rel="noreferrer">
{t("browse_our_docs")}
</a>
.
</div>
{/* visible on mobile */}
<div className="text-subtle bg-muted w-full p-5 md:hidden">
<p className="">{t("specific_issue")}</p>
<button
className="hover:text-emphasis text-defualt font-medium underline"
onClick={async () => {
setActive(true);
if (isFreshChatEnabled) {
setFreshChat(true);
} else if (isInterComEnabled) {
await open();
} else {
loadChat({ open: true });
}
onHelpItemSelect();
}}>
{t("contact_support")}
</button>
) : (
<a
href={JOIN_DISCORD}
target="_blank"
className="hover:text-emphasis text-defualt font-medium underline">
{t("community_support")}
</a>
)}
onHelpItemSelect();
}}>
{t("contact_support")}
</button>
<span> {t("or").toLowerCase()} </span>
<a
onClick={() => onHelpItemSelect()}
@@ -1,26 +0,0 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useIntercom } from "./useIntercom";
interface IntercomMenuItemProps {
onHelpItemSelect: () => void;
}
export default function IntercomMenuItem(props: IntercomMenuItemProps) {
const { onHelpItemSelect } = props;
const { t } = useLocale();
const { open } = useIntercom();
// eslint-disable-next-line turbo/no-undeclared-env-vars
if (!process.env.NEXT_PUBLIC_INTERCOM_APP_ID) return null;
return (
<button
onClick={async () => {
await open();
onHelpItemSelect();
}}
className="hover:bg-subtle hover:text-emphasis text-default flex w-full px-5 py-2 pr-4 text-sm font-medium">
{t("contact_support")}
</button>
);
}
@@ -17,6 +17,7 @@ const useIntercomHook = isInterComEnabled
return {
boot: noop,
show: noop,
shutdown: noop,
};
};
@@ -26,6 +27,37 @@ export const useIntercom = () => {
const { hasPaidPlan } = useHasPaidPlan();
const { hasTeamPlan } = useHasTeamPlan();
const boot = async () => {
let userHash;
const req = await fetch(`/api/intercom-hash`);
const res = await req.json();
if (res?.hash) {
userHash = res.hash;
}
hookData.boot({
...(data && data?.name && { name: data.name }),
...(data && data?.email && { email: data.email }),
...(data && data?.id && { userId: data.id }),
createdAt: String(dayjs(data?.createdDate).unix()),
...(userHash && { userHash }),
customAttributes: {
//keys should be snake cased
user_name: data?.username,
link: `${WEBSITE_URL}/${data?.username}`,
admin_link: `${WEBAPP_URL}/settings/admin/users/${data?.id}/edit`,
identity_provider: data?.identityProvider,
timezone: data?.timeZone,
locale: data?.locale,
has_paid_plan: hasPaidPlan,
has_team_plan: hasTeamPlan,
metadata: data?.metadata,
is_logged_in: !!data,
},
});
};
const open = async () => {
let userHash;
@@ -57,7 +89,7 @@ export const useIntercom = () => {
});
hookData.show();
};
return { ...hookData, open };
return { ...hookData, open, boot };
};
export default useIntercom;
+11
View File
@@ -19,6 +19,7 @@ import {
} from "@calcom/features/ee/organizations/components/OrgUpgradeBanner";
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
import HelpMenuItem from "@calcom/features/ee/support/components/HelpMenuItem";
import useIntercom from "@calcom/features/ee/support/lib/intercom/useIntercom";
import { TeamsUpgradeBanner, type TeamsUpgradeBannerProps } from "@calcom/features/ee/teams/components";
import { useFlagMap } from "@calcom/features/flags/context/provider";
import { KBarContent, KBarRoot, KBarTrigger } from "@calcom/features/kbar/Kbar";
@@ -52,8 +53,10 @@ import { useFormbricks } from "@calcom/lib/formbricks-client";
import getBrandColours from "@calcom/lib/getBrandColours";
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
import useTheme from "@calcom/lib/hooks/useTheme";
import { isKeyInObject } from "@calcom/lib/isKeyInObject";
import { localStorage } from "@calcom/lib/webstorage";
import type { User } from "@calcom/prisma/client";
import { trpc } from "@calcom/trpc/react";
import useEmailVerifyCheck from "@calcom/trpc/react/hooks/useEmailVerifyCheck";
@@ -213,8 +216,16 @@ const useBanners = () => {
const Layout = (props: LayoutProps) => {
const banners = useBanners();
const showIntercom = localStorage.getItem("showIntercom");
const isMobile = useMediaQuery("(max-width: 768px)");
const { boot } = useIntercom();
const pageTitle = typeof props.heading === "string" && !props.title ? props.heading : props.title;
useEffect(() => {
if (showIntercom === "false" || isMobile) return;
boot();
}, [showIntercom, isMobile]);
const bannersHeight = useMemo(() => {
const activeBanners =
banners &&