Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 11 commits into from
Apr 11, 2024
Merged
10 changes: 0 additions & 10 deletions apps/web/modules/event-types/views/event-types-listing-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
2 changes: 0 additions & 2 deletions packages/features/ee/support/components/ContactMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -20,7 +19,6 @@ export default function ContactMenuItem(props: ContactMenuItem) {
<>
{hasPaidPlan ? (
<>
<IntercomMenuItem onHelpItemSelect={onHelpItemSelect} />
<ZendeskMenuItem onHelpItemSelect={onHelpItemSelect} />
<HelpscoutMenuItem onHelpItemSelect={onHelpItemSelect} />
<FreshChatMenuItem onHelpItemSelect={onHelpItemSelect} />
Expand Down
85 changes: 60 additions & 25 deletions packages/features/ee/support/components/HelpMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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({
Expand All @@ -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">
Expand All @@ -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>
Expand Down Expand Up @@ -188,33 +192,64 @@ 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) {
await open();
} 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()}
Expand Down
26 changes: 0 additions & 26 deletions packages/features/ee/support/lib/intercom/IntercomMenuItem.tsx

This file was deleted.

34 changes: 33 additions & 1 deletion packages/features/ee/support/lib/intercom/useIntercom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const useIntercomHook = isInterComEnabled
return {
boot: noop,
show: noop,
shutdown: noop,
};
};

Expand All @@ -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;

Expand Down Expand Up @@ -57,7 +89,7 @@ export const useIntercom = () => {
});
hookData.show();
};
return { ...hookData, open };
return { ...hookData, open, boot };
};

export default useIntercom;
11 changes: 11 additions & 0 deletions packages/features/shell/Shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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 &&
Expand Down