feat(homepage): add analytics (#1474)

This commit is contained in:
Mamadou DICKO 2023-10-24 13:55:42 +02:00 committed by GitHub
parent f91247c6c7
commit 31ecde773a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 208 additions and 60 deletions

View File

@ -1,64 +1,18 @@
import Link from "next/link";
import { useTranslation } from "react-i18next";
import { AiFillStar } from "react-icons/ai";
import { LuChevronRight } from "react-icons/lu";
import { cn } from "@/lib/utils";
import { PopoverMenuMobile } from "./components/PopoverMenuMobile";
import { QuivrLogo } from "./components/QuivrLogo";
import { NavbarItem } from "./types";
import { useHomeHeader } from "./hooks/useHomeHeader";
import { linkStyle } from "./styles";
type HomeNavProps = {
color?: "white" | "black";
};
export const HomeHeader = ({ color = "white" }: HomeNavProps): JSX.Element => {
const { t } = useTranslation("home");
const linkStyle = {
white: "text-white hover:text-slate-200",
black: "text-black",
};
const navItems: NavbarItem[] = [
{
href: "https://theodo.co.uk",
label: `${t("sponsored_by")} Theodo`,
rightIcon: null,
newTab: true,
className: "underline",
},
{
href: "https://github.com/StanGirard/quivr",
label: t("star_us"),
leftIcon: <AiFillStar size={16} className="hidden md:inline" />,
rightIcon: null,
},
{ href: "/blog", label: t("blog"), rightIcon: null, newTab: true },
{ href: "/signup", label: t("sign_up") },
{ href: "/login", label: t("sign_in") },
];
const navLinks = (device: "mobile" | "desktop") =>
navItems.map(
({ href, label, leftIcon, rightIcon, newTab = false, className }) => (
<li key={label}>
<Link
href={href}
{...(newTab && { target: "_blank", rel: "noopener noreferrer" })}
className={cn(
"flex justify-between items-center hover:text-primary p-2 gap-1",
device === "desktop" ? linkStyle[color] : null,
className
)}
>
{leftIcon}
{label}
{rightIcon !== null && (rightIcon ?? <LuChevronRight size={16} />)}
</Link>
</li>
)
);
const { navLinks } = useHomeHeader({ color });
return (
<header className="w-screen flex justify-between items-center p-5 min-w-max md:max-w-6xl m-auto">

View File

@ -0,0 +1,71 @@
import Link from "next/link";
import { useTranslation } from "react-i18next";
import { AiFillStar } from "react-icons/ai";
import { LuChevronRight } from "react-icons/lu";
import { useHomepageTracking } from "@/app/(home)/hooks/useHomepageTracking";
import { cn } from "@/lib/utils";
import { linkStyle } from "../styles";
import { NavbarItem } from "../types";
type UseHomeHeaderProps = {
color: "white" | "black";
};
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useHomeHeader = ({ color }: UseHomeHeaderProps) => {
const { t } = useTranslation("home");
const { onLinkClick } = useHomepageTracking();
const navItems: NavbarItem[] = [
{
href: "https://theodo.co.uk",
label: `${t("sponsored_by")} Theodo`,
rightIcon: null,
newTab: true,
className: "underline",
},
{ href: "/blog", label: t("blog"), rightIcon: null, newTab: true },
{
href: "https://github.com/StanGirard/quivr",
label: t("star_us"),
leftIcon: <AiFillStar size={16} className="hidden md:inline" />,
rightIcon: null,
},
{ href: "/signup", label: t("sign_up") },
{ href: "/login", label: t("sign_in") },
];
const navLinks = (device: "mobile" | "desktop") =>
navItems.map(
({ href, label, leftIcon, rightIcon, newTab = false, className }) => (
<li key={label}>
<Link
href={href}
onClick={(event) => {
onLinkClick({
href,
label,
event,
});
}}
{...(newTab && { target: "_blank", rel: "noopener noreferrer" })}
className={cn(
"flex justify-between items-center hover:text-primary p-2 gap-1",
device === "desktop" ? linkStyle[color] : null,
className
)}
>
{leftIcon}
{label}
{rightIcon !== null && (rightIcon ?? <LuChevronRight size={16} />)}
</Link>
</li>
)
);
return {
navLinks,
};
};

View File

@ -0,0 +1,4 @@
export const linkStyle = {
white: "text-white hover:text-slate-200",
black: "text-black",
};

View File

@ -3,6 +3,7 @@ import Link from "next/link";
import { useTranslation } from "react-i18next";
import { LuChevronRight } from "react-icons/lu";
import { useHomepageTracking } from "@/app/(home)/hooks/useHomepageTracking";
import { DEMO_VIDEO_DATA_KEY } from "@/lib/api/cms/config";
import { useCmsApi } from "@/lib/api/cms/useCmsApi";
import Button from "@/lib/components/ui/Button";
@ -13,7 +14,7 @@ import { VideoPlayer } from "./components/VideoPlayer";
export const DemoSection = (): JSX.Element => {
const { t } = useTranslation("home", { keyPrefix: "demo" });
const { getDemoVideoUrl } = useCmsApi();
const { onLinkClick } = useHomepageTracking();
const { data: demoVideoUrl } = useQuery({
queryKey: [DEMO_VIDEO_DATA_KEY],
queryFn: getDemoVideoUrl,
@ -29,7 +30,16 @@ export const DemoSection = (): JSX.Element => {
<Spinner />
)}
</div>
<Link href="/signup">
<Link
href="/signup"
onClick={(event) => {
onLinkClick({
href: "/signup",
label: "SIGN_UP",
event,
});
}}
>
<Button className="mt-2 rounded-full">
{t("start_now")} <LuChevronRight size={24} />
</Button>

View File

@ -7,8 +7,11 @@ import { RiTwitterXLine } from "react-icons/ri";
import Button from "@/lib/components/ui/Button";
import { GITHUB_URL, LINKEDIN_URL, TWITTER_URL } from "@/lib/config/CONSTANTS";
import { useHomepageTracking } from "../../hooks/useHomepageTracking";
export const FooterSection = (): JSX.Element => {
const { t } = useTranslation("home", { keyPrefix: "footer" });
const { onLinkClick } = useHomepageTracking();
return (
<div className="flex flex-col items-center gap-10 text-white text-center text-lg">
@ -17,13 +20,31 @@ export const FooterSection = (): JSX.Element => {
{t("description_1")} <br /> {t("description_2")}{" "}
</p>
<div className="flex items-center justify-center gap-5 flex-wrap">
<Link href="/signup">
<Link
href="/signup"
onClick={(event) => {
onLinkClick({
href: "/signup",
label: "SIGN_UP",
event,
});
}}
>
<Button className=" rounded-full">
{t("start_using")}
<LuChevronRight size={24} />
</Button>
</Link>
<Link href="/contact">
<Link
href="/contact"
onClick={(event) => {
onLinkClick({
href: "/contact",
label: "CONTACT",
event,
});
}}
>
<Button variant="tertiary">
{t("contact_sales")} <LuChevronRight size={24} />
</Button>

View File

@ -5,10 +5,13 @@ import { LuChevronRight } from "react-icons/lu";
import Button from "@/lib/components/ui/Button";
import { useHomepageTracking } from "../../hooks/useHomepageTracking";
export const IntroSection = (): JSX.Element => {
const { t } = useTranslation("home", { keyPrefix: "intro" });
const laptopImage = "/Homepage/laptop-demo.png";
const smartphoneImage = "/Homepage/smartphone-demo.png";
const { onLinkClick } = useHomepageTracking();
return (
<>
@ -22,12 +25,30 @@ export const IntroSection = (): JSX.Element => {
<p className="text-xl">{t("subtitle")}</p>
</div>
<div className="flex flex-col items-start sm:flex-row sm:items-center gap-5">
<Link href="/signup">
<Link
href="/signup"
onClick={(event) =>
onLinkClick({
href: "/signup",
label: "SIGN_UP",
event,
})
}
>
<Button className="text-white bg-black rounded-full">
{t("try_demo")} <LuChevronRight size={24} />
</Button>
</Link>
<Link href="/contact">
<Link
href="/contact"
onClick={(event) => {
onLinkClick({
href: "/contact",
label: "CONTACT_SALES",
event,
});
}}
>
<Button variant="tertiary" className="font-semibold">
{t("contact_sales")} <LuChevronRight size={24} />
</Button>

View File

@ -14,10 +14,13 @@ import {
import Button from "@/lib/components/ui/Button";
import Spinner from "@/lib/components/ui/Spinner";
import { useHomepageTracking } from "../../hooks/useHomepageTracking";
export const SecuritySection = (): JSX.Element => {
const { t } = useTranslation("home", {
keyPrefix: "security",
});
const { onLinkClick } = useHomepageTracking();
const { getSecurityQuestions } = useCmsApi();
@ -53,7 +56,16 @@ export const SecuritySection = (): JSX.Element => {
</div>
</div>
<div className="flex md:justify-end w-full">
<Link href="/signup">
<Link
href="/signup"
onClick={(event) => {
onLinkClick({
href: "/signup",
label: "SIGN_UP",
event,
});
}}
>
<Button className="rounded-full">
{t("cta")}
<LuChevronRight size={24} />

View File

@ -5,9 +5,11 @@ import { LuChevronRight } from "react-icons/lu";
import Button from "@/lib/components/ui/Button";
import { UseCasesListing } from "./components/UseCasesListing/UseCasesListing";
import { useHomepageTracking } from "../../hooks/useHomepageTracking";
export const UseCases = (): JSX.Element => {
const { t } = useTranslation("home");
const { onLinkClick } = useHomepageTracking();
return (
<div className="text-white w-full">
@ -19,7 +21,16 @@ export const UseCases = (): JSX.Element => {
</div>
<UseCasesListing />
<div className="mt-10 flex md:justify-center">
<Link href="/signup">
<Link
href="/signup"
onClick={(event) => {
onLinkClick({
href: "/signup",
label: "SIGN_UP",
event,
});
}}
>
<Button className="bg-black rounded-full">
{t("intro.try_demo")} <LuChevronRight size={24} />
</Button>

View File

@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { LuPanelLeft } from "react-icons/lu";
import { useHomepageTracking } from "@/app/(home)/hooks/useHomepageTracking";
import { USE_CASES_DATA_KEY } from "@/lib/api/cms/config";
import { useCmsApi } from "@/lib/api/cms/useCmsApi";
import Spinner from "@/lib/components/ui/Spinner";
@ -12,7 +13,7 @@ import { UseCaseComponent } from "./components/UseCaseComponent";
export const UseCasesListing = (): JSX.Element => {
const { getUseCases } = useCmsApi();
const { onButtonClick } = useHomepageTracking();
const { data: cases = [], isLoading } = useQuery({
queryKey: [USE_CASES_DATA_KEY],
queryFn: getUseCases,
@ -37,13 +38,23 @@ export const UseCasesListing = (): JSX.Element => {
);
}
const handleUseCaseClick = (id: string) => {
onButtonClick({
label: `USE_CASES_${id}`,
});
if (!isMobile) {
return;
}
setSelectedCaseId(id);
};
return (
<div className="grid grid-cols-6 md:gap-10 flex-column items-start ">
<div className={"col-span-6 md:col-span-2 flex flex-col gap-3"}>
{cases.map((c) => (
<div
key={c.id}
onClick={() => !isMobile && setSelectedCaseId(c.id)}
onClick={() => handleUseCaseClick(c.id)}
className={cn(
"p-6 rounded-lg cursor-pointer",
selectedCaseId === c.id &&

View File

@ -27,7 +27,7 @@ export const UseCaseComponent = ({
</div>
</Fragment>
))}
<div className="flex mt-1 flex-col w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl bg-white dark:bg-black border border-black/10 dark:border-white/25 p-4 mt-10">
<div className="flex flex-col w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl bg-white dark:bg-black border border-black/10 dark:border-white/25 p-4 mt-10">
<div className="flex items-center">
<PiPaperclipFill className="text-3xl" />
<span className="text-[#BFBFBF]">@Einstein</span>

View File

@ -0,0 +1,33 @@
import { useRouter } from "next/navigation";
import { MouseEvent } from "react";
import { useEventTracking } from "@/services/analytics/june/useEventTracking";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useHomepageTracking = () => {
const { track } = useEventTracking();
const router = useRouter();
const onLinkClick = ({
href,
label,
event,
}: {
href: string;
label: string;
event: MouseEvent<HTMLAnchorElement>;
}) => {
event.preventDefault();
void track(`HOMEPAGE-${label}`);
router.push(href);
};
const onButtonClick = ({ label }: { label: string }) => {
void track(`HOMEPAGE-${label}`);
};
return {
onLinkClick,
onButtonClick,
};
};