Files
igny8/frontend/src/pages/Payment.tsx
2026-01-01 21:42:04 +00:00

123 lines
4.6 KiB
TypeScript

import { useEffect, useMemo, useState } from "react";
import { useLocation, useNavigate, Link } from "react-router-dom";
import { useAuthStore } from "../store/authStore";
import InputField from "../components/form/input/InputField";
import TextArea from "../components/form/input/TextArea";
import Label from "../components/form/Label";
import Button from "../components/ui/button/Button";
const PLAN_COPY: Record<string, { name: string; price: string; content: string }> = {
starter: { name: "Starter", price: "$49/mo", content: "50 content pieces/month" },
growth: { name: "Growth", price: "$149/mo", content: "200 content pieces/month" },
scale: { name: "Scale", price: "$349/mo", content: "500 content pieces/month" },
};
export default function Payment() {
const location = useLocation();
const navigate = useNavigate();
const user = useAuthStore((s) => s.user);
const [contactEmail, setContactEmail] = useState("");
const [note, setNote] = useState("");
const [error, setError] = useState("");
const planSlug = useMemo(() => new URLSearchParams(location.search).get("plan") || "", [location.search]);
const plan = useMemo(() => {
const slugFromAccount = user?.account?.plan?.slug;
const slug = planSlug || slugFromAccount || "";
return slug ? PLAN_COPY[slug] : null;
}, [planSlug, user?.account?.plan?.slug]);
const mailtoHref = useMemo(() => {
if (!plan || !contactEmail.trim()) return "";
const subject = encodeURIComponent(`Payment submitted for ${plan.name}`);
const body = encodeURIComponent(
`Plan: ${plan.name}\nAccount: ${user?.account?.slug || user?.account?.id || "-"}\nEmail: ${contactEmail}\nNotes/Reference: ${note || "-"}`
);
return `mailto:sales@igny8.com?subject=${subject}&body=${body}`;
}, [plan, contactEmail, note, user?.account?.slug, user?.account?.id]);
useEffect(() => {
if (!plan || !user) {
navigate("/pricing", { replace: true });
}
}, [plan, navigate, user]);
const handleRequest = (e: React.MouseEvent<HTMLAnchorElement>) => {
if (!plan) {
e.preventDefault();
navigate("/pricing", { replace: true });
return;
}
if (!contactEmail.trim()) {
e.preventDefault();
setError("Please enter a contact email.");
return;
}
setError("");
};
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4 py-16">
<div className="w-full max-w-3xl bg-white rounded-2xl shadow-lg p-8 space-y-6 border border-gray-100">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-500">Confirm your plan</p>
<h1 className="text-2xl font-semibold text-gray-900">Complete your subscription</h1>
</div>
<Link to="/pricing" className="text-sm text-brand-600 hover:text-brand-700">
Change plan
</Link>
</div>
{plan && (
<div className="rounded-xl border border-gray-200 bg-gray-50 p-4">
<h2 className="text-lg font-semibold text-gray-900">{plan.name}</h2>
<p className="text-gray-700">{plan.price}</p>
<p className="text-sm text-gray-600">{plan.content}</p>
<p className="text-xs text-warning-700 mt-2">
Payment is completed offline (bank transfer). Submit your email and reference below; we will verify and activate your account.
</p>
</div>
)}
<div className="space-y-4">
<InputField
label="Contact email"
type="email"
value={contactEmail}
onChange={(e) => setContactEmail(e.target.value)}
placeholder="you@example.com"
/>
<div>
<Label className="mb-2">Notes (optional)</Label>
<TextArea
value={note}
onChange={(value) => setNote(value)}
placeholder="Company name, billing contact, or questions"
rows={3}
/>
</div>
</div>
<div className="flex items-center justify-between">
<Link to="/signup" className="text-sm text-gray-600 hover:text-gray-800">
Prefer the free plan? Start your trial
</Link>
<Button
onClick={() => {
if (mailtoHref && contactEmail.trim()) {
window.location.href = mailtoHref;
}
}}
disabled={!contactEmail.trim()}
variant="primary"
>
Request payment instructions
</Button>
</div>
{error && <p className="text-sm text-error-600">{error}</p>}
</div>
</div>
);
}