Skip to content

Commit 85d165b

Browse files
authored
feat: added hubspot embed to newsletter button
2 parents 7691a9b + 3fa246c commit 85d165b

File tree

2 files changed

+223
-5
lines changed

2 files changed

+223
-5
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { Button } from "@/components/ui/button";
2+
import { Input } from "@/components/ui/input";
3+
import { CheckCircle2, Loader2, Mail } from "lucide-react";
4+
import { useState } from "react";
5+
6+
const PORTAL_ID = "47519938";
7+
const FORM_ID = "2d808d3b-402c-4b34-a9aa-36ffe5026063";
8+
9+
function getCookie(name: string) {
10+
const value = "; " + document.cookie;
11+
const parts = value.split("; " + name + "=");
12+
if (parts.length === 2) return parts.pop()?.split(";").shift();
13+
}
14+
15+
export function SubscribeForm() {
16+
const [email, setEmail] = useState("");
17+
const [error, setError] = useState("");
18+
const [submitError, setSubmitError] = useState("");
19+
const [isSubmitting, setIsSubmitting] = useState(false);
20+
const [submitted, setSubmitted] = useState(false);
21+
22+
function validate() {
23+
if (!email) {
24+
setError("Email is required.");
25+
return false;
26+
}
27+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
28+
setError("Please enter a valid email address.");
29+
return false;
30+
}
31+
return true;
32+
}
33+
34+
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
35+
e.preventDefault();
36+
setSubmitError("");
37+
38+
if (!validate()) return;
39+
40+
setIsSubmitting(true);
41+
42+
const submission = {
43+
fields: [{ name: "email", value: email }],
44+
context: {
45+
hutk: getCookie("hubspotutk"),
46+
pageUri: window.location.href,
47+
pageName: document.title,
48+
},
49+
};
50+
51+
try {
52+
const res = await fetch(
53+
`https://api.hsforms.com/submissions/v3/integration/submit/${PORTAL_ID}/${FORM_ID}`,
54+
{
55+
method: "POST",
56+
headers: { "Content-Type": "application/json" },
57+
body: JSON.stringify(submission),
58+
},
59+
);
60+
61+
if (res.ok) {
62+
setSubmitted(true);
63+
} else {
64+
setSubmitError("Submission failed. Please try again.");
65+
}
66+
} catch {
67+
setSubmitError("Submission failed. Please try again.");
68+
} finally {
69+
setIsSubmitting(false);
70+
}
71+
}
72+
73+
if (submitted) {
74+
return (
75+
<div className="flex flex-col items-center justify-center gap-5 py-8 text-center animate-in fade-in zoom-in duration-300">
76+
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-green-50 dark:bg-green-500/10">
77+
<CheckCircle2 className="h-10 w-10 text-green-500" />
78+
</div>
79+
<div>
80+
<h3 className="text-xl font-bold text-foreground">
81+
You're subscribed!
82+
</h3>
83+
<p className="mt-2 text-sm text-para">
84+
Thank you for signing up. You'll start receiving the latest updates
85+
from Akash Network shortly.
86+
</p>
87+
</div>
88+
</div>
89+
);
90+
}
91+
92+
return (
93+
<div className="flex flex-col gap-6">
94+
{/* Header */}
95+
<div className="flex flex-col gap-2">
96+
<div className="flex items-center gap-2">
97+
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-primary/10">
98+
<Mail className="h-4 w-4 text-primary" />
99+
</div>
100+
<span className="text-xs font-semibold uppercase tracking-widest text-primary">
101+
Newsletter
102+
</span>
103+
</div>
104+
<h2 className="text-2xl font-bold leading-tight text-foreground">
105+
Sign up for Akash Network's Newsletter
106+
</h2>
107+
<p className="text-sm leading-relaxed text-para">
108+
Enter your email below to stay up to date with the latest from Akash
109+
Network.
110+
</p>
111+
</div>
112+
113+
{/* Form */}
114+
<form onSubmit={handleSubmit} noValidate className="flex flex-col gap-4">
115+
{submitError && (
116+
<div className="rounded-md bg-red-50 dark:bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400">
117+
{submitError}
118+
</div>
119+
)}
120+
121+
<div className="flex flex-col gap-1">
122+
<label
123+
htmlFor="subscribe-email"
124+
className="text-sm font-medium text-foreground/80"
125+
>
126+
Email address <span className="text-primary">*</span>
127+
</label>
128+
<Input
129+
id="subscribe-email"
130+
name="email"
131+
type="email"
132+
placeholder="you@example.com"
133+
value={email}
134+
onChange={(e) => {
135+
setEmail(e.target.value);
136+
setError("");
137+
}}
138+
className="h-11 border border-border bg-background text-foreground placeholder:text-para/50 focus:border-primary focus:ring-primary"
139+
/>
140+
{error && <p className="text-xs text-red-500">{error}</p>}
141+
</div>
142+
143+
<Button
144+
type="submit"
145+
disabled={isSubmitting}
146+
className="h-11 w-full font-semibold bg-primary text-primary-foreground hover:bg-primary/90"
147+
>
148+
{isSubmitting ? (
149+
<span className="flex items-center justify-center gap-2">
150+
<Loader2 className="h-4 w-4 animate-spin" />
151+
Subscribing...
152+
</span>
153+
) : (
154+
"Subscribe Now"
155+
)}
156+
</Button>
157+
158+
<p className="text-center text-xs text-para/60">
159+
No spam, ever. Unsubscribe at any time.
160+
</p>
161+
</form>
162+
</div>
163+
);
164+
}
Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,64 @@
11
---
2-
import { subscribeLink } from "@/lib/constants";
3-
import { ArrowUpCircle } from "lucide-react";
2+
import { ArrowUpCircle, X } from "lucide-react";
3+
import { SubscribeForm } from "@/components/footer/SubscribeForm";
44
---
55

6-
<a
7-
href={subscribeLink}
6+
<button
7+
id="open-hubspot-form"
88
class="flex cursor-pointer items-center justify-center rounded-md border border-primary bg-primary/5 px-[13px] py-2 text-sm font-medium text-primary transition-all duration-300 hover:bg-primary hover:text-white dark:border-primary"
9-
><ArrowUpCircle className="mr-2 h-4 w-4 rotate-45" />Subscribe Now</a
109
>
10+
<ArrowUpCircle className="mr-2 h-4 w-4 rotate-45" />
11+
Subscribe Now
12+
</button>
13+
14+
<div
15+
id="subscribe-modal"
16+
class="fixed inset-0 hidden items-center justify-center bg-black/60 z-50 p-4 backdrop-blur-sm"
17+
>
18+
<div class="bg-background2 border border-border rounded-2xl w-full max-w-md relative shadow-2xl p-8 transform transition-all">
19+
<button
20+
id="close-subscribe-modal"
21+
class="absolute top-4 right-4 text-para hover:text-primary transition-colors p-1 rounded-full hover:bg-primary/5"
22+
aria-label="Close"
23+
>
24+
<X className="h-5 w-5" />
25+
</button>
26+
27+
<SubscribeForm client:only="react" />
28+
</div>
29+
</div>
30+
31+
<script>
32+
function setupSubscribeModal() {
33+
const openBtn = document.getElementById("open-hubspot-form");
34+
const closeBtn = document.getElementById("close-subscribe-modal");
35+
const modal = document.getElementById("subscribe-modal");
36+
37+
if (openBtn && modal) {
38+
openBtn.addEventListener("click", () => {
39+
modal.classList.remove("hidden");
40+
modal.classList.add("flex");
41+
});
42+
}
43+
44+
if (closeBtn && modal) {
45+
closeBtn.addEventListener("click", () => {
46+
modal.classList.add("hidden");
47+
modal.classList.remove("flex");
48+
});
49+
}
50+
51+
// Close on backdrop click
52+
if (modal) {
53+
modal.addEventListener("click", (e) => {
54+
if (e.target === modal) {
55+
modal.classList.add("hidden");
56+
modal.classList.remove("flex");
57+
}
58+
});
59+
}
60+
}
61+
62+
setupSubscribeModal();
63+
document.addEventListener("astro:page-load", setupSubscribeModal);
64+
</script>

0 commit comments

Comments
 (0)