fastpocket/Frontend/app/(admin)/pricing/page.tsx

197 lines
6.2 KiB
TypeScript

"use client";
import React, { useEffect } from "react";
import PageHeader from "@/sections/PageHeader";
import { Price, Product, SourceModal } from "@/types";
import { Check } from "@styled-icons/entypo/Check";
import { ChangeEventHandler, useState } from "react";
import { apiPrices } from "./actions";
import Newsletter from "@/sections/Newsletter/Newsletter";
import { createCheckoutSession, isAuthenticated } from "@/app/(auth)/actions";
import { toast } from "react-toastify";
import { useRouter } from "next/navigation";
export default function PricingPage() {
const [isAnnual, setIsAnnual] = useState(false);
const [products, setProducts] = useState<Product[]>([]);
const handleToggle = () => {
setIsAnnual((prev) => !prev);
};
useEffect(() => {
(async () => {
const resposeProducts: Product[] = await apiPrices();
setProducts(resposeProducts);
})();
}, []);
return (
<main
id="content"
role="main"
className="h-full flex flex-col min-h-screen mx-auto w-screen overflow-hidden"
>
<PageHeader
title="Pricing"
subtitle={
<>
{" "}
<h2 className="h3 text-primary-content content text-center max-w-6xl mx-auto px-6">
Select a subscription plan for your team or try advanced
functionality for free.
</h2>
</>
}
/>
<div className="flex items-center justify-center mt-10">
<PriceToggle isAnnual={isAnnual} onChange={handleToggle} />
</div>
<div className="max-w-6xl mx-auto mb-24 h-full">
<div
className={`w-screen lg:w-full flex gap-x-4 lg:justify-center gap-y-8 px-6 pt-12 overflow-x-scroll`}
>
{products.map((x, i) => (
<PriceCard key={i} product={x} isAnnual={isAnnual} />
))}
</div>
</div>
<Newsletter />
</main>
);
}
function PriceCard({
product,
isAnnual,
}: {
product: Product;
isAnnual: boolean;
}) {
const router = useRouter();
const openSignUpModalOnPriceClick = (price: Price) => {
const signUpModal = document.getElementById("sign-up-modal");
if (!signUpModal) return;
signUpModal.setAttribute("price_id", price.price_id);
signUpModal.setAttribute("name", SourceModal.SignUpViaPurchase);
signUpModal.click();
};
const generateCheckoutPage = async (price: Price) => {
try {
const checkoutSessionResponse = await createCheckoutSession(
price.price_id
);
router.push(checkoutSessionResponse.url);
} catch (error) {
if (error instanceof Error) {
toast.error(error.message, {
position: "bottom-left",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "colored",
});
}
}
};
const submitForm = async (price: Price) => {
const userIsAuthenticated = await isAuthenticated();
if (userIsAuthenticated) {
await generateCheckoutPage(price);
} else {
openSignUpModalOnPriceClick(price);
}
};
return (
<div className="relative w-64 sm:w-80 bg-gray-100 dark:bg-gray-800 p-6">
<div className="flex flex-col h-full">
<div className="mb-12 relative">
{false && (
<p className="absolute top-[-10px] left-[50%] -translate-x-1/2 font-architects-daughter text-xl text-pink-default text-center">
Popular
</p>
)}
<h1 className="text-center text-3xl font-inter font-bold pt-6 text-black dark:text-white">
{product.name}
</h1>
<h3 className="text-center pt-4 text-black dark:text-white">
{product.description}
</h3>
</div>
<div className="pb-12">
<ul className="flex flex-col gap-y-3 mx-12">
{product.metadata?.benefits?.map((x, i) => (
<li key={i} className="flex items-center gap-x-4 flex-nowrap">
<Check className=" self-start" color="#FF0DCA" size={24} />
<p className="w-40 text-black dark:text-white overflow-clip text-ellipsis">
{x}
</p>
</li>
))}
</ul>
</div>
<div className="flex flex-col mx-auto mt-auto">
<div className="flex flex-row mx-auto gap-x-4 justify-center items-center mb-2">
<h1 className="h2 text-black dark:text-white">
$
{isAnnual
? product.yearlyPrice.unit_amount / 100
: product.monthlyPrice.unit_amount / 100}
</h1>
<p className="w-16 leading-5 text-sm text-black dark:text-white">
per user per {isAnnual ? "year" : "month"}
</p>
</div>
<button
onClick={() =>
submitForm(isAnnual ? product.yearlyPrice : product.monthlyPrice)
}
className=" mx-auto flex text-sm font-semibold py-2 px-20 m-2 text-white bg-gradient-to-r from-pink-default to-purple-default rounded-full mb-4 cursor-pointer group-hover:animate-bounce"
>
Try it!
</button>
</div>
</div>
</div>
);
}
function PriceToggle({
isAnnual,
onChange,
}: {
isAnnual: boolean;
onChange?: ChangeEventHandler<HTMLInputElement>;
}) {
return (
<>
<label className="themeSwitcherTwo shadow-card relative inline-flex cursor-pointer select-none items-center justify-center rounded-sm dark:bg-gray-550 p-1">
<input
type="checkbox"
className="sr-only"
checked={isAnnual}
onChange={onChange}
/>
<span
className={`flex items-center space-x-[6px] rounded py-2 px-[18px] text-sm font-medium ${
!isAnnual ? "text-white bg-pink-550" : "text-body-color"
}`}
>
Monthly Billing
</span>
<span
className={`flex items-center space-x-[6px] rounded py-2 px-[18px] text-sm font-medium ${
isAnnual ? "text-white bg-pink-550" : "text-body-color"
}`}
>
Yearly Billing
</span>
</label>
</>
);
}