TorbatYar/frontend/modules/commercial/features/landing-marketing.tsx

337 lines
15 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { Badge, Button, Container } from "@/components/ui";
import { useAuth } from "@/hooks/useAuth";
import { useTheme } from "@/hooks/useTheme";
import {
loadCommercialBundles,
loadCommercialPricing,
loadCommercialProducts,
} from "../adapters";
import { commercialGet, extractItems } from "../adapters/http";
import type { CommercialBundle, CommercialPricingItem, CommercialProduct } from "../types";
import {
commercialDescription,
commercialEntityName,
enumLabel,
formatMoney,
} from "../presentation";
const JOURNEY = [
"کشف نیاز",
"پیشنهاد هوشمند",
"بسته و قیمت",
"آزمایش رایگان",
"فضای کاری",
"شروع کار",
];
const FAQ = [
{
q: "آیا می‌توانم بدون کارت بانکی شروع کنم؟",
a: "بله. پس از ساخت فضای کاری می‌توانید دوره آزمایشی را بدون کارت بانکی فعال کنید.",
},
{
q: "بعداً می‌توانم محصول جدید اضافه کنم؟",
a: "بله. هر زمان نیازتان بیشتر شد، محصولات و امکانات تازه را از داشبورد اضافه کنید.",
},
{
q: "دامنه اختصاصی کی باز می‌شود؟",
a: "پس از فعال‌شدن اشتراک می‌توانید دامنه اختصاصی متصل کنید؛ در دوره آزمایشی زیردامنه رایگان دارید.",
},
{
q: "آیا قیمت‌ها شفاف هستند؟",
a: "بله. هزینه ماهانه و سالانه هر پلن پیش از انتخاب به‌صورت شفاف نمایش داده می‌شود.",
},
];
export function CommercialMarketingLanding() {
const { theme } = useTheme();
const { isAuthenticated, login, loading: authLoading } = useAuth();
const siteName = theme?.site_name ?? "TorbatYar";
const [products, setProducts] = useState<CommercialProduct[]>([]);
const [bundles, setBundles] = useState<CommercialBundle[]>([]);
const [pricing, setPricing] = useState<CommercialPricingItem[]>([]);
const [businessTypes, setBusinessTypes] = useState<
Array<{ business_type_code: string; display_name: string }>
>([]);
useEffect(() => {
void Promise.all([
loadCommercialProducts(),
loadCommercialBundles(),
loadCommercialPricing(),
commercialGet<unknown>("/api/v1/commercial/business-types"),
]).then(([p, b, pr, bt]) => {
if (p.availability === "ready") setProducts(p.data.filter((x) => x.visibility !== "hidden"));
if (b.availability === "ready") setBundles(b.data);
if (pr.availability === "ready") setPricing(pr.data.slice(0, 4));
if (bt.ok) {
setBusinessTypes(
extractItems<{ business_type_code: string; display_name: string }>(bt.data, [
"items",
"business_types",
])
);
}
});
}, []);
return (
<div className="pb-20">
{/* Hero — one composition, brand-first, full-bleed atmosphere */}
<section className="relative min-h-[min(92vh,820px)] overflow-hidden">
<div
className="absolute inset-0"
style={{
background:
"radial-gradient(ellipse 80% 60% at 70% 20%, rgba(2,132,199,0.22), transparent 55%), radial-gradient(ellipse 50% 40% at 10% 80%, rgba(15,23,42,0.08), transparent 50%), linear-gradient(165deg, #0b1220 0%, #0f2744 42%, #0c4a6e 100%)",
}}
/>
<div
className="pointer-events-none absolute inset-0 opacity-[0.12]"
style={{
backgroundImage:
"url(\"data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='1'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\")",
}}
/>
<Container className="relative flex min-h-[min(92vh,820px)] flex-col justify-center py-16">
<p className="text-sm font-semibold tracking-[0.2em] text-sky-200/90">{siteName}</p>
<h1 className="mt-4 max-w-3xl text-4xl font-extrabold leading-[1.15] text-white sm:text-5xl lg:text-6xl">
سیستمعامل کسبوکار شما روی ابر
</h1>
<p className="mt-5 max-w-xl text-base leading-8 text-sky-100/85 sm:text-lg">
از شناخت نیاز تا شروع کار؛ محصولات، بستهها و قیمتها همیشه شفاف و بهروز هستند.
</p>
<div className="mt-9 flex flex-wrap gap-3">
<Link href="/discover">
<Button size="lg" className="bg-white text-secondary hover:bg-sky-50">
شروع آزمایش رایگان
</Button>
</Link>
<Link href="/pricing">
<Button
size="lg"
variant="outline"
className="border-white/40 bg-transparent text-white hover:bg-white/10"
>
مقایسه قیمت
</Button>
</Link>
{isAuthenticated ? (
<Link href="/dashboard">
<Button size="lg" variant="ghost" className="text-sky-100 hover:bg-white/10">
داشبورد
</Button>
</Link>
) : (
<Button
size="lg"
variant="ghost"
className="text-sky-100 hover:bg-white/10"
loading={authLoading}
onClick={() => login()}
>
ورود
</Button>
)}
</div>
</Container>
</section>
{/* Business selector teaser */}
<section className="border-b border-gray-100 bg-white py-16 dark:border-gray-800 dark:bg-gray-950">
<Container>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">کشف کسبوکار</h2>
<p className="mt-2 max-w-2xl text-sm text-gray-600 dark:text-gray-400">
چند سؤال ساده پاسخ دهید تا محصولات و بسته مناسب کسبوکار شما پیشنهاد شود.
</p>
<div className="mt-8 flex flex-wrap gap-2">
{businessTypes.length ? (
businessTypes.slice(0, 12).map((t) => (
<Link
key={t.business_type_code}
href={`/discover?type=${encodeURIComponent(t.business_type_code)}`}
className="rounded-full border border-gray-200 px-4 py-2 text-sm text-secondary transition hover:border-primary hover:bg-[var(--color-primary-soft)] dark:border-gray-700 dark:text-gray-200"
>
{commercialEntityName("business-types", t.business_type_code, t.display_name)}
</Link>
))
) : (
<Link href="/discover">
<Button>شروع ارزیابی کسبوکار</Button>
</Link>
)}
</div>
</Container>
</section>
{/* Product ecosystem */}
<section className="py-16">
<Container>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">اکوسیستم محصولات</h2>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-400">
ابزارهای یکپارچه برای فروش، ارتباط با مشتری، مدیریت و رشد کسبوکار.
</p>
{products.length ? (
<ul className="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{products.slice(0, 9).map((p) => (
<li
key={p.product_code}
className="border-b border-gray-100 pb-4 dark:border-gray-800"
>
<p className="font-semibold text-secondary dark:text-gray-100">
{commercialEntityName("products", p.product_code, p.display_name)}
</p>
<p className="mt-1 text-xs text-gray-500">
{commercialDescription("products", p.description)}
</p>
</li>
))}
</ul>
) : (
<p className="mt-6 text-sm text-gray-500">
محصولات قابل ارائه بهزودی اینجا نمایش داده میشوند.
</p>
)}
</Container>
</section>
{/* Feature / industry / bundle / pricing teasers */}
<section className="bg-[var(--surface-muted)] py-16 dark:bg-gray-900/40">
<Container className="space-y-14">
<div>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">قابلیتهای پلتفرم</h2>
<p className="mt-2 max-w-2xl text-sm text-gray-600 dark:text-gray-400">
پیشنهاد هوشمند، مدیریت اشتراک، دامنه اختصاصی، گزارش مصرف و دسترسی یکپارچه به محصولات.
</p>
</div>
<div>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">صنایع</h2>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-400">
راهکارهای متناسب با مدل کاری و اندازه کسبوکار شما.
</p>
{!businessTypes.length ? (
<p className="mt-4 text-sm text-gray-500">فهرست صنایع در حال بهروزرسانی است.</p>
) : null}
</div>
<div>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">بستههای پیشنهادی</h2>
{bundles.length ? (
<ul className="mt-6 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{bundles.slice(0, 6).map((b) => (
<li key={b.bundle_code}>
<p className="text-lg font-bold text-secondary dark:text-gray-100">
{commercialEntityName("bundles", b.bundle_code, b.display_name)}
</p>
<p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
{commercialDescription("bundles", b.description)}
</p>
{b.recommendation_badge ? (
<Badge variant="primary" className="mt-2">
{enumLabel(b.recommendation_badge)}
</Badge>
) : null}
</li>
))}
</ul>
) : (
<p className="mt-4 text-sm text-gray-500">بستههای قابل ارائه در حال آمادهسازی هستند.</p>
)}
<Link href="/discover" className="mt-6 inline-block text-sm font-semibold text-primary">
مقایسه و انتخاب بسته
</Link>
</div>
<div>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">نمای قیمت</h2>
{pricing.length ? (
<ul className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{pricing.map((item) => (
<li key={item.pricing_item_code}>
<p className="font-semibold text-secondary dark:text-gray-100">
{commercialEntityName("pricing", item.pricing_item_code, item.display_name)}
</p>
<p className="mt-1 text-xs text-gray-500">
{enumLabel(item.pricing_model)} · {formatMoney(item.amount_minor, item.currency)}
</p>
</li>
))}
</ul>
) : (
<p className="mt-4 text-sm text-gray-500">قیمت پلنها بهزودی اعلام میشود.</p>
)}
<Link href="/pricing" className="mt-6 inline-block text-sm font-semibold text-primary">
مشاهده کامل قیمتگذاری
</Link>
</div>
</Container>
</section>
{/* Customer journey */}
<section className="py-16">
<Container>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">مسیر مشتری</h2>
<ol className="mt-8 grid gap-4 sm:grid-cols-3 lg:grid-cols-6">
{JOURNEY.map((step, i) => (
<li key={step} className="text-sm">
<span className="font-mono text-xs text-primary">{String(i + 1).padStart(2, "0")}</span>
<p className="mt-1 font-semibold text-secondary dark:text-gray-100">{step}</p>
</li>
))}
</ol>
</Container>
</section>
{/* Trust + FAQ + CTA */}
<section className="border-t border-gray-100 bg-white py-16 dark:border-gray-800 dark:bg-gray-950">
<Container className="grid gap-12 lg:grid-cols-2">
<div>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">اعتماد سازمانی</h2>
<ul className="mt-4 space-y-2 text-sm text-gray-600 dark:text-gray-400">
<li>چندمستأجری و SSO یکپارچه</li>
<li>دامنه اختصاصی و گواهی SSL</li>
<li>قیمتگذاری شفاف و قابل ارتقا</li>
<li>پشتیبانی از رشد چندشعبهای</li>
</ul>
</div>
<div>
<h2 className="text-2xl font-bold text-secondary dark:text-gray-100">سوالات متداول</h2>
<dl className="mt-4 space-y-4">
{FAQ.map((item) => (
<div key={item.q}>
<dt className="text-sm font-semibold text-secondary dark:text-gray-100">{item.q}</dt>
<dd className="mt-1 text-sm text-gray-600 dark:text-gray-400">{item.a}</dd>
</div>
))}
</dl>
</div>
</Container>
<Container className="mt-14 text-center">
<h2 className="text-3xl font-extrabold text-secondary dark:text-gray-100">
آماده ساخت فضای کاری هستید؟
</h2>
<p className="mx-auto mt-3 max-w-lg text-sm text-gray-600 dark:text-gray-400">
ارزیابی را شروع کنید، بسته مناسب را انتخاب کنید و رایگان وارد داشبورد شوید.
</p>
<div className="mt-8 flex flex-wrap justify-center gap-3">
<Link href="/discover">
<Button size="lg">شروع رایگان</Button>
</Link>
<Link href="/register?redirect=/onboarding">
<Button size="lg" variant="outline">
ثبتنام
</Button>
</Link>
</div>
</Container>
</section>
</div>
);
}