Fix FE
This commit is contained in:
parent
1241132095
commit
54a5c3ca9a
28 changed files with 826 additions and 422 deletions
|
|
@ -8,6 +8,7 @@ import BottomIllustration from './BottomIllustration';
|
|||
import { TickerValue } from '../ui/TickerValue';
|
||||
import { ChevronIcon, LogoIcon, PlayIcon } from '../ui/icons';
|
||||
import { trackEvent } from '../../lib/analytics';
|
||||
import { apiUrl } from '../../lib/api';
|
||||
|
||||
const BRAND_NAME = 'Perfect Postcode';
|
||||
const BRAND_TEXT_CLASS = 'text-teal-600 dark:text-teal-400';
|
||||
|
|
@ -163,11 +164,78 @@ function ProductDemoVideo() {
|
|||
);
|
||||
}
|
||||
|
||||
interface PriceStripTier {
|
||||
up_to: number | null;
|
||||
price_pence: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact pricing teaser under the hero CTAs: surfaces the current lifetime
|
||||
* price and tier scarcity that otherwise hide behind the Pricing nav link.
|
||||
*/
|
||||
function PriceStrip({
|
||||
onOpenPricing,
|
||||
hidePricing,
|
||||
}: {
|
||||
onOpenPricing: () => void;
|
||||
hidePricing?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [pricing, setPricing] = useState<{
|
||||
licensed_count: number;
|
||||
current_price_pence: number;
|
||||
tiers: PriceStripTier[];
|
||||
} | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (hidePricing) return;
|
||||
const controller = new AbortController();
|
||||
fetch(apiUrl('pricing'), { signal: controller.signal })
|
||||
.then((res) => (res.ok ? res.json() : null))
|
||||
.then(setPricing)
|
||||
.catch(() => {});
|
||||
return () => controller.abort();
|
||||
}, [hidePricing]);
|
||||
|
||||
if (hidePricing || !pricing) return null;
|
||||
|
||||
const price = `£${pricing.current_price_pence / 100}`;
|
||||
const currentTier = pricing.tiers.find(
|
||||
(tier) => tier.up_to === null || pricing.licensed_count < tier.up_to
|
||||
);
|
||||
const spotsRemaining =
|
||||
currentTier?.up_to != null ? currentTier.up_to - pricing.licensed_count : 0;
|
||||
|
||||
return (
|
||||
<p className="text-sm text-warm-300 mb-2">
|
||||
{pricing.current_price_pence === 0
|
||||
? t('upgrade.freeForEarly')
|
||||
: t('home.priceStrip', { price })}{' '}
|
||||
{pricing.current_price_pence > 0 && spotsRemaining > 0 && (
|
||||
<span className="font-semibold text-teal-300">
|
||||
{spotsRemaining === 1
|
||||
? t('home.priceStripSpots', { count: spotsRemaining })
|
||||
: t('home.priceStripSpotsPlural', { count: spotsRemaining })}
|
||||
</span>
|
||||
)}{' '}
|
||||
<button
|
||||
onClick={() => {
|
||||
trackEvent('CTA Click', { location: 'hero', label: 'price_strip' });
|
||||
onOpenPricing();
|
||||
}}
|
||||
className="underline decoration-dotted underline-offset-2 text-teal-300 hover:text-teal-200"
|
||||
>
|
||||
{t('home.priceStripCta')}
|
||||
</button>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomePage({
|
||||
onOpenDashboard,
|
||||
onOpenPricing: _onOpenPricing,
|
||||
onOpenPricing,
|
||||
theme = 'light',
|
||||
hidePricing: _hidePricing,
|
||||
hidePricing,
|
||||
}: {
|
||||
onOpenDashboard: () => void;
|
||||
onOpenPricing: () => void;
|
||||
|
|
@ -327,7 +395,7 @@ export default function HomePage({
|
|||
<p className="text-base md:text-lg text-warm-200 mb-8 max-w-xl">
|
||||
{highlightBrandText(t('home.heroDescription'), 'font-semibold text-teal-300')}
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4 mb-10">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4 mb-5">
|
||||
<button
|
||||
onClick={() => {
|
||||
trackEvent('CTA Click', { location: 'hero', label: 'explore_map' });
|
||||
|
|
@ -347,6 +415,8 @@ export default function HomePage({
|
|||
{t('home.seeTheDifference')}
|
||||
</button>
|
||||
</div>
|
||||
<PriceStrip onOpenPricing={onOpenPricing} hidePricing={hidePricing} />
|
||||
<p className="text-sm text-warm-400 mb-8">{t('home.coverageNote')}</p>
|
||||
<div className="home-hero-stats flex flex-wrap pt-3 border-t border-white/10">
|
||||
<div className="home-hero-stat">
|
||||
<div className="home-hero-stat-value">
|
||||
|
|
@ -356,7 +426,7 @@ export default function HomePage({
|
|||
</div>
|
||||
<div className="home-hero-stat">
|
||||
<div className="home-hero-stat-value">
|
||||
<TickerValue text="56" active={statsActive} />
|
||||
<TickerValue text="40+" active={statsActive} />
|
||||
</div>
|
||||
<div className="home-hero-stat-label">{t('home.statFilters')}</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue