import React from "react"; import { CreditCard, ShoppingBag, ArrowRight, Loader2, AlertCircle } from "lucide-react"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { TenantWelcomeLayout, WelcomeStepCard, OnboardingCTAList, useOnboardingProgress, } from ".."; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; import { FrostedSurface } from "../../components/tenant/frosted-surface"; import { ADMIN_BILLING_PATH, ADMIN_WELCOME_SUMMARY_PATH } from "../../constants"; import { useTenantPackages } from "../hooks/useTenantPackages"; import { Package } from "../../api"; const DEFAULT_CURRENCY = "EUR"; function useLocaleFormats(locale: string) { const currencyFormatter = React.useMemo( () => new Intl.NumberFormat(locale, { style: "currency", currency: DEFAULT_CURRENCY, minimumFractionDigits: 0, }), [locale] ); const dateFormatter = React.useMemo( () => new Intl.DateTimeFormat(locale, { year: "numeric", month: "2-digit", day: "2-digit", }), [locale] ); return { currencyFormatter, dateFormatter }; } function formatFeatureLabel(t: ReturnType["t"], key: string): string { const translationKey = `packages.features.${key}`; const translated = t(translationKey); if (translated !== translationKey) { return translated; } return key .split("_") .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(" "); } export default function WelcomePackagesPage() { const navigate = useNavigate(); const { markStep } = useOnboardingProgress(); const packagesState = useTenantPackages(); const { t, i18n } = useTranslation("onboarding"); const locale = i18n.language?.startsWith("en") ? "en-GB" : "de-DE"; const { currencyFormatter, dateFormatter } = useLocaleFormats(locale); React.useEffect(() => { if (packagesState.status === "success") { const active = packagesState.activePackage; markStep({ packageSelected: Boolean(active), lastStep: "packages", selectedPackage: active ? { id: active.package_id, name: active.package_name, priceText: typeof active.price === "number" ? currencyFormatter.format(active.price) : t("packages.card.onRequest"), isSubscription: Boolean(active.package_limits?.subscription), } : null, serverStep: active ? "package_selected" : undefined, meta: active ? { packages: [active.package_id], is_active: active.active, } : undefined, }); } }, [packagesState, markStep, currencyFormatter, t]); const handleSelectPackage = React.useCallback( (pkg: Package) => { const priceText = typeof pkg.price === "number" ? currencyFormatter.format(pkg.price) : t("packages.card.onRequest"); markStep({ packageSelected: true, lastStep: "packages", selectedPackage: { id: pkg.id, name: pkg.name, priceText, isSubscription: Boolean(pkg.features?.subscription), }, serverStep: "package_selected", meta: { packages: [pkg.id] }, }); navigate(ADMIN_WELCOME_SUMMARY_PATH, { state: { packageId: pkg.id } }); }, [currencyFormatter, markStep, navigate, t] ); const renderPackageList = () => { if (packagesState.status === "loading") { return ( {t("packages.state.loading")} ); } if (packagesState.status === "error") { return ( {t("packages.state.errorTitle")} {packagesState.message ?? t("packages.state.errorDescription")} ); } if (packagesState.status === "success" && packagesState.catalog.length === 0) { return ( {t("packages.state.emptyTitle")} {t("packages.state.emptyDescription")} ); } if (packagesState.status !== "success") { return null; } return (
{packagesState.catalog.map((pkg) => { const isActive = packagesState.activePackage?.package_id === pkg.id; const purchased = packagesState.purchasedPackages.find((tenantPkg) => tenantPkg.package_id === pkg.id); const featureLabels = Object.entries(pkg.features ?? {}) .filter(([, enabled]) => Boolean(enabled)) .map(([key]) => formatFeatureLabel(t, key)); const isSubscription = Boolean(pkg.features?.subscription); const priceText = typeof pkg.price === "number" ? currencyFormatter.format(pkg.price ?? 0) : t("packages.card.onRequest"); const badges: string[] = []; if (pkg.max_guests) { badges.push(t("packages.card.badges.guests", { count: pkg.max_guests })); } if (pkg.gallery_days) { badges.push(t("packages.card.badges.days", { count: pkg.gallery_days })); } if (pkg.max_photos) { badges.push(t("packages.card.badges.photos", { count: pkg.max_photos })); } return (

{t(isSubscription ? "packages.card.subscription" : "packages.card.creditPack")}

{pkg.name}

{priceText}

{pkg.max_photos ? t("packages.card.descriptionWithPhotos", { count: pkg.max_photos }) : t("packages.card.description")}

{badges.map((badge) => ( {badge} ))} {featureLabels.map((feature) => ( {feature} ))} {isActive ? ( {t("packages.card.active")} ) : null}
{purchased ? (

{t("packages.card.purchased", { date: purchased.purchased_at ? dateFormatter.format(new Date(purchased.purchased_at)) : t("packages.card.purchasedUnknown"), })}

) : null}
); })}
); }; return ( {renderPackageList()} navigate(ADMIN_WELCOME_SUMMARY_PATH), icon: ArrowRight, }, ]} /> ); }