diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx index 2b8fefe82c..cee918f7e8 100644 --- a/apps/web/src/components/footer.tsx +++ b/apps/web/src/components/footer.tsx @@ -1,8 +1,14 @@ +import { useForm } from "@tanstack/react-form"; +import { useMutation } from "@tanstack/react-query"; import { Link, useRouterState } from "@tanstack/react-router"; -import { ExternalLinkIcon, MailIcon } from "lucide-react"; -import { useState } from "react"; +import { ArrowRightIcon, ExternalLinkIcon, MailIcon } from "lucide-react"; +import { useEffect, useRef, useState } from "react"; + +import { Checkbox } from "@hypr/ui/components/ui/checkbox"; +import { cn } from "@hypr/utils"; import { Image } from "@/components/image"; +import { addContact } from "@/functions/loops"; function getNextRandomIndex(length: number, prevIndex: number): number { if (length <= 1) return 0; @@ -57,6 +63,67 @@ export function Footer() { } function BrandSection({ currentYear }: { currentYear: number }) { + const [expanded, setExpanded] = useState(false); + const [email, setEmail] = useState(""); + const [subscriptions, setSubscriptions] = useState({ + releaseNotesStable: false, + releaseNotesBeta: false, + newsletter: false, + }); + const containerRef = useRef(null); + + useEffect(() => { + if (!expanded) return; + + const handleClickOutside = (event: MouseEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + setExpanded(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, [expanded]); + + const mutation = useMutation({ + mutationFn: async () => { + await addContact({ + data: { + email, + userGroup: "Subscriber", + source: "FOOTER", + releaseNotesStable: subscriptions.releaseNotesStable, + releaseNotesBeta: subscriptions.releaseNotesBeta, + newsletter: subscriptions.newsletter, + }, + }); + }, + onSuccess: () => { + setExpanded(false); + setEmail(""); + setSubscriptions({ + releaseNotesStable: false, + releaseNotesBeta: false, + newsletter: false, + }); + }, + }); + + const form = useForm({ + defaultValues: { email: "" }, + onSubmit: async ({ value }) => { + setEmail(value.email); + }, + }); + + const hasSelection = + subscriptions.releaseNotesStable || + subscriptions.releaseNotesBeta || + subscriptions.newsletter; + return (
@@ -67,15 +134,135 @@ function BrandSection({ currentYear }: { currentYear: number }) { />

Fastrepl © {currentYear}

-

- Are you in back-to-back meetings?{" "} - + {expanded && ( +

+

+ What would you like to receive? +

+ +
+
+

+ Release Notes +

+ + +
+ +
+

+ Newsletter +

+ +
+
+ + {mutation.isError && ( +

+ Something went wrong. Please try again. +

+ )} +
+ )} + +
{ + e.preventDefault(); + if (expanded && hasSelection && email) { + mutation.mutate(); + } + }} + className={cn([ + "max-w-72 border border-neutral-100 bg-white transition-all laptop:border-l-0", + expanded && "shadow-lg", + ])} > - Get started - -

+ + {(field) => ( +
+ + { + field.handleChange(e.target.value); + setEmail(e.target.value); + }} + onFocus={() => setExpanded(true)} + placeholder={ + expanded ? "Enter your email" : "Subscribe to updates" + } + className={cn([ + "min-w-0 flex-1 pl-8 pr-2 py-1.5 text-sm", + "bg-transparent placeholder:text-neutral-400", + "focus:outline-none", + ])} + /> + +
+ )} +
+
+
+