feat: add waitlist signup count

This commit is contained in:
Maze Winther
2025-06-22 14:25:19 +02:00
parent 6e84dcaffb
commit e84caf3f9f
3 changed files with 52 additions and 8 deletions

View File

@ -1,11 +1,14 @@
import { Hero } from "@/components/landing/hero"; import { Hero } from "@/components/landing/hero";
import { Header } from "@/components/header"; import { Header } from "@/components/header";
import { getWaitlistCount } from "@/lib/waitlist";
export default async function Home() {
const signupCount = await getWaitlistCount();
export default function Home() {
return ( return (
<div> <div>
<Header /> <Header />
<Hero /> <Hero signupCount={signupCount} />
</div> </div>
); );
} }

View File

@ -6,18 +6,25 @@ import { Input } from "../ui/input";
import { ArrowRight } from "lucide-react"; import { ArrowRight } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useState } from "react"; import { useState } from "react";
import { toast } from "sonner"; import { useToast } from "@/hooks/use-toast";
export function Hero() { interface HeroProps {
signupCount: number;
}
export function Hero({ signupCount }: HeroProps) {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const { toast } = useToast();
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (!email.trim()) { if (!email.trim()) {
toast.error("Email required", { toast({
title: "Email required",
description: "Please enter your email address.", description: "Please enter your email address.",
variant: "destructive",
}); });
return; return;
} }
@ -36,16 +43,23 @@ export function Hero() {
const data = await response.json(); const data = await response.json();
if (response.ok) { if (response.ok) {
toast.success("Welcome to the waitlist! 🎉"); toast({
title: "Welcome to the waitlist! 🎉",
description: "You'll be notified when we launch.",
});
setEmail(""); setEmail("");
} else { } else {
toast.error("Oops!", { toast({
title: "Oops!",
description: data.error || "Something went wrong. Please try again.", description: data.error || "Something went wrong. Please try again.",
variant: "destructive",
}); });
} }
} catch (error) { } catch (error) {
toast.error("Network error", { toast({
title: "Network error",
description: "Please check your connection and try again.", description: "Please check your connection and try again.",
variant: "destructive",
}); });
} finally { } finally {
setIsSubmitting(false); setIsSubmitting(false);
@ -113,6 +127,18 @@ export function Hero() {
</Button> </Button>
</form> </form>
</motion.div> </motion.div>
{signupCount > 0 && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.8, duration: 0.6 }}
className="mt-6 inline-flex items-center gap-2 bg-muted/30 px-4 py-2 rounded-full text-sm text-muted-foreground"
>
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />
<span>{signupCount.toLocaleString()} people already joined</span>
</motion.div>
)}
</motion.div> </motion.div>
<motion.div <motion.div

View File

@ -0,0 +1,15 @@
import { db } from "@/lib/db";
import { waitlist } from "@/lib/db/schema";
import { sql } from "drizzle-orm";
export async function getWaitlistCount() {
try {
const result = await db
.select({ count: sql<number>`count(*)` })
.from(waitlist);
return result[0]?.count || 0;
} catch (error) {
console.error("Failed to fetch waitlist count:", error);
return 0;
}
}