Skip to content

Donation calculator landing #3596

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

Merged
merged 16 commits into from
Apr 30, 2025
File renamed without changes.
Binary file added src/components/video/bg-calculator.webp
Binary file not shown.
1 change: 1 addition & 0 deletions src/components/video/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { videos, Video } from "./video";
40 changes: 32 additions & 8 deletions src/components/about-video.tsx → src/components/video/video.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
import poster from "assets/images/about-video-preview.webp";
import { useEffect, useRef, useState } from "react";
import subtitle from "./about-video.vtt";
import aboutSubtitle from "./about.vtt";
import aboutPoster from "./about.webp";
import bgCalculatorPoster from "./bg-calculator.webp";

type VideoStatus = "loading" | "error" | "loaded";

const videoUrl =
"https://elktqtbc25yfiipw.public.blob.vercel-storage.com/about-better-giving-HXqlfIWwctto66xyOTStih3rWj9Ajg";
export const AboutVideo = ({ classes = "" }) => {
interface Vid {
url: string;
poster: string;
subtitle?: string;
}
interface Props {
classes?: string;
vid: Vid;
}

export const videos = {
about: {
url: "https://elktqtbc25yfiipw.public.blob.vercel-storage.com/about-better-giving-HXqlfIWwctto66xyOTStih3rWj9Ajg",
poster: aboutPoster,
subtitle: aboutSubtitle,
},
donation_calculator: {
url: "https://elktqtbc25yfiipw.public.blob.vercel-storage.com/donation-calculator-SZju4lCvUjU6HUYWi2adrQVR9NDCaz",
poster: bgCalculatorPoster,
},
};

export const Video = ({ classes = "", vid }: Props) => {
const videoRef = useRef<HTMLVideoElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [isIntersecting, setIsIntersecting] = useState<boolean>(false);
Expand Down Expand Up @@ -67,18 +88,21 @@ export const AboutVideo = ({ classes = "" }) => {
</div>
)}
<video
poster={poster}
src={videoUrl}
poster={vid.poster}
src={vid.url}
ref={videoRef}
className={`absolute top-0 left-0 w-full h-full object-cover`}
playsInline
controls
autoPlay
muted
loop
preload="none"
onError={handleError}
>
<track
kind="captions"
src={subtitle}
src={vid.subtitle}
srcLang="en"
label="English"
default
Expand Down
31 changes: 31 additions & 0 deletions src/hooks/use-hubspot-don-calculator-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect, useState } from "react";

type State = "loading" | "loaded" | "error";

export function useHubspotDonCalculatorForm() {
const [state, setState] = useState<State | undefined>();

//biome-ignore lint: no deps
useEffect(() => {
function load() {
if (state === "loading" || state === "loaded") return;
setState("loading");
const script = document.createElement("script");
script.src = "https://js-eu1.hsforms.net/forms/embed/24900163.js";
script.defer = true;

script.onload = () => {
setState("loaded");
};

script.onerror = () => {
setState("error");
};

document.body.appendChild(script);
}
load();
}, []);

return { state };
}
Empty file.
4 changes: 2 additions & 2 deletions src/pages/home/feature1.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Link } from "@remix-run/react";
import { laira } from "assets/laira/laira";
import { AboutVideo } from "components/about-video";
import Image from "components/image";
import { Video, videos } from "components/video/video";
import { BOOK_A_DEMO } from "constants/env";
import { appRoutes } from "constants/routes";
import { ArrowRight } from "lucide-react";
Expand Down Expand Up @@ -52,7 +52,7 @@ export function Feature1({ className = "" }) {
long-term financial sustainability.
</p>

<AboutVideo classes="max-w-2xl justify-self-center p-4" />
<Video classes="max-w-2xl justify-self-center p-4" vid={videos.about} />

<ul className="mt-20 lg:divide-x divide-gray-l3 grid gap-y-20 lg:gap-y-0 lg:grid-cols-3">
{items.map((item, idx) => (
Expand Down
7 changes: 5 additions & 2 deletions src/pages/informational/nonprofit-info/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from "@remix-run/react";
import { AboutVideo } from "components/about-video";
import { Video, videos } from "components/video/video";
import { BOOK_A_DEMO } from "constants/env";
import { appRoutes } from "constants/routes";

Expand Down Expand Up @@ -38,7 +38,10 @@ export default function Hero({ className = "" }) {
</Link>
</div>
</div>
<AboutVideo classes="max-w-2xl @6xl:max-w-auto order-1 @6xl:order-2 w-full self-center" />
<Video
classes="max-w-2xl @6xl:max-w-auto order-1 @6xl:order-2 w-full self-center"
vid={videos.about}
/>
{/* <Image
src={benefits.donors[1].img}
width={420}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/landing-a/feature.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { laira } from "assets/laira/laira";
import { AboutVideo } from "components/about-video";
import Image from "components/image";
import { Video, videos } from "components/video/video";

type TListItem = {
title1: string;
Expand Down Expand Up @@ -50,7 +50,7 @@ export function Feature({ className = "" }) {
</p>
</div>

<AboutVideo classes="max-w-2xl justify-self-center p-4" />
<Video vid={videos.about} classes="max-w-2xl justify-self-center p-4" />

<ul className="col-span-full mt-10 lg:divide-x divide-gray-l3 grid gap-y-20 lg:gap-y-0 lg:grid-cols-3">
{items.map((item, idx) => (
Expand Down
49 changes: 49 additions & 0 deletions src/pages/landing-d/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Link } from "@remix-run/react";
import type { MetaFunction } from "@vercel/remix";
import { Footer } from "components/footer";
import { DappLogo } from "components/image";
import { appRoutes } from "constants/routes";
import { metas } from "helpers/seo";
import { Top } from "./top";
export const meta: MetaFunction = () =>
metas({
title: "You’re Losing Donations - Find Out How Much | Better Giving",
description:
"Don’t let lost fees, idle cash, and missed gifts drain your nonprofit’s revenue. Use the free Better Giving Donation Calculator to see what you’re missing in under a minute.",
url: "https://better.giving/see-what-youre-losing",
});
export default function Component() {
return (
<main className="w-full grid content-start pb-16 @container">
<div
className="sticky top-[-1px] z-50 bg-white"
ref={(node) => {
if (!node) return;
const observer = new IntersectionObserver(
([e]) => {
const isIntersecting = e.intersectionRatio < 1;
e.target.classList.toggle("bg-white", isIntersecting);
e.target.classList.toggle("shadow-lg", isIntersecting);
},
{ threshold: [1] }
);
observer.observe(node);
}}
>
<div className="xl:container xl:mx-auto px-10 py-4 flex justify-between gap-x-4 items-center">
<DappLogo classes="h-12" />
<Link
to={appRoutes.signup}
className="btn btn-blue max-xl:text-sm normal-case text-nowrap px-6 py-2 rounded-full"
>
Sign up
</Link>
</div>
</div>

<Top classes="xl:container xl:mx-auto px-10 bg-transparent mt-16 mb-28" />

<Footer classes="xl:container xl:mx-auto px-10" />
</main>
);
}
97 changes: 97 additions & 0 deletions src/pages/landing-d/top.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { useNavigate } from "@remix-run/react";
import { Modal } from "components/modal";
import { Video, videos } from "components/video";
import { useHubspotDonCalculatorForm } from "hooks/use-hubspot-don-calculator-form";
import { useState } from "react";

export function Top({ classes = "" }) {
const [open, setOpen] = useState(false);
const navigate = useNavigate();
const { state } = useHubspotDonCalculatorForm();
return (
<section
className={`${classes} grid grid-cols-1 lg:grid-cols-2 gap-12 p-4 @container`}
>
<div className="h-fit self-center relative">
<Tooltip className="max-xl:hidden absolute -right-24 z-10" />
<Video
vid={videos.donation_calculator}
classes="relative shadow-xl shadow-black/10 rounded-lg"
/>
</div>
<div>
<h1 className="text-4.5xl leading-snug max-lg:text-center text-right">
<div className="relative w-fit max-lg:mx-auto lg:ml-auto text-nowrap">
You're Losing Donations{" "}
<span className="absolute bottom-2 left-0 w-full h-4 bg-blue-l3 -z-10"></span>
</div>
</h1>
<p className="mb-4 text-gray-d4 text-lg max-lg:text-center text-right mt-4">
Thousands of dollars are slipping through the cracks every year – lost
to fees, idle cash, and outdated donation methods.
</p>
<p className="mb-4 text-gray-d4 font-semibold text-lg max-lg:text-center text-right mt-4">
The longer you wait, the more you miss.
</p>
<div className="mb-4 text-gray-d4 text-lg max-lg:text-center text-right">
See see exactly how much revenue is being left on the table – and how
quickly you could turn that around.
</div>
<button
onClick={() => {
if (state !== "loaded") {
return navigate("/donation-calculator");
}
setOpen(true);
}}
type="button"
className="mt-8 shadow-xl capitalize shadow-black/10 btn btn-blue text-center lg:text-right justify-self-center lg:justify-self-end rounded-lg py-4 px-8 w-full md:w-auto"
>
See what you're losing
</button>
{open && (
<Modal
classes="fixed-center z-10 grid text-gray-d4 bg-white w-[calc(100%-2.5rem)] max-w-4xl rounded-lg"
open={open}
onClose={() => setOpen(false)}
>
<div
className="hs-form-frame"
data-region="eu1"
data-form-id="17bb2a2b-322c-4a8c-b8d6-50bb1a59881c"
data-portal-id="24900163"
/>
</Modal>
)}

<p className="max-lg:text-center text-right text-sm text-gray mt-2">
"It takes less than a minute — find out how much you're leaving on the
table."
</p>
</div>
</section>
);
}

function Tooltip({ className = "" }) {
return (
<span className={`text-gray-d4 ${className}`}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="99"
height="50.6"
viewBox="0 0 90.2 49.5"
fill="none"
className="rotate-320"
>
<path
d="M86.5184 47.9261C86.9386 48.7464 87.891 49.0896 88.7113 48.6694C89.5316 48.2492 89.8748 47.2968 89.4546 46.4765L86.5184 47.9261ZM0.750315 12.1702C0.292122 12.8603 0.480187 13.7913 1.17037 14.2495L12.4175 21.7161C13.1077 22.1743 14.0387 21.9863 14.4969 21.2961C14.955 20.6059 14.767 19.675 14.0768 19.2168L4.07932 12.5797L10.7164 2.58225C11.1746 1.89207 10.9865 0.961128 10.2963 0.502936C9.60613 0.0447435 8.67518 0.232808 8.21699 0.92299L0.750315 12.1702ZM89.4546 46.4765C82.5494 32.4322 74.5 21.0234 61.0685 14.6649C47.6713 8.3195 29.2413 7.1537 1.87328 12.6825L2.46732 15.6231C28.8433 10.0943 46.2017 11.7514 58.6565 17.6475C71.0773 23.5315 78.7006 33.7177 86.5184 47.9261L89.4546 46.4765Z"
fill="#183244"
/>
</svg>
<p className="text-gray-d4 -top-6 left-8 relative -rotate-[12deg] font-gochi text-nowrap">
Watch how it works!
</p>
</span>
);
}
1 change: 1 addition & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const rmx = remix({
r("donate-fund/:fundId", "./pages/donate-fund/redirect.ts");
r("fundraisers/:fundId/donate", "./pages/donate-fund/index.tsx");
r("donate-thanks", "./pages/donate-thanks.tsx");
r("see-what-youre-losing", "./pages/landing-d/index.tsx");
r("simplify-fundraising-maximize-impact", "./pages/landing-a/index.tsx", {
id: "page-a",
});
Expand Down