Add POI feature and imporve the overall backend implementation

This commit is contained in:
Urtzi Alfaro
2025-11-12 15:34:10 +01:00
parent e8096cd979
commit 5783c7ed05
173 changed files with 16862 additions and 9078 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Button } from '../../components/ui';
import { Button, ScrollReveal, FloatingCTA, AnimatedCounter } from '../../components/ui';
import { PublicLayout } from '../../components/layout';
import { PricingSection } from '../../components/subscription';
import { getRegisterUrl, getDemoUrl } from '../../utils/navigation';
@@ -26,6 +26,7 @@ import {
const LandingPage: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<PublicLayout
@@ -38,26 +39,42 @@ const LandingPage: React.FC = () => {
variant: "default"
}}
>
{/* Floating CTA - appears after scrolling */}
<FloatingCTA
text={t('landing:hero.cta_primary', 'Únete al Programa Piloto')}
onClick={() => navigate(getRegisterUrl())}
icon={<ArrowRight className="w-4 h-4" />}
position="bottom-right"
showAfterScroll={600}
dismissible
/>
{/* Hero Section */}
<section className="relative py-20 lg:py-32 bg-gradient-to-br from-[var(--bg-primary)] via-[var(--bg-secondary)] to-[var(--color-primary)]/5">
<section className="relative py-20 lg:py-32 bg-gradient-to-br from-[var(--bg-primary)] via-[var(--bg-secondary)] to-[var(--color-primary)]/5 overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center">
{/* Pre-headline */}
<div className="mb-4">
<p className="text-sm md:text-base font-medium text-[var(--text-tertiary)]">
{t('landing:hero.pre_headline', 'Para Panaderías que Pierden €500-2,000/Mes en Desperdicios')}
</p>
</div>
{/* Scarcity Badge */}
<div className="mb-6 inline-block">
<div className="bg-gradient-to-r from-amber-50 via-orange-50 to-amber-50 dark:from-amber-900/20 dark:via-orange-900/20 dark:to-amber-900/20 border-2 border-amber-400 dark:border-amber-500 rounded-full px-6 py-3 shadow-lg">
<div className="mb-8 inline-block">
<div className="bg-gradient-to-r from-amber-50 via-orange-50 to-amber-50 dark:from-amber-900/20 dark:via-orange-900/20 dark:to-amber-900/20 border-2 border-amber-400 dark:border-amber-500 rounded-full px-6 py-3 shadow-lg hover:shadow-xl transition-shadow">
<p className="text-sm font-bold text-amber-700 dark:text-amber-300">
🔥 {t('landing:hero.scarcity', 'Solo 12 plazas restantes de 20 • 3 meses GRATIS')}
</p>
</div>
</div>
<h1 className="text-4xl tracking-tight font-extrabold text-[var(--text-primary)] sm:text-5xl lg:text-7xl">
<span className="block">{t('landing:hero.title_line1', 'Aumenta Ganancias,')}</span>
<span className="block text-[var(--color-primary)]">{t('landing:hero.title_line2', 'Reduce Desperdicios')}</span>
<h1 className="text-4xl tracking-tight font-extrabold text-[var(--text-primary)] sm:text-5xl lg:text-7xl leading-tight">
<span className="block">{t('landing:hero.title_option_a_line1', 'Ahorra €500-2,000 al Mes')}</span>
<span className="block text-[var(--color-primary)] mt-2">{t('landing:hero.title_option_a_line2', 'Produciendo Exactamente Lo Que Venderás')}</span>
</h1>
<p className="mt-6 max-w-3xl mx-auto text-lg text-[var(--text-secondary)] sm:text-xl">
{t('landing:hero.subtitle', 'IA que predice demanda con datos de tu zona para que produzcas exactamente lo que vas a vender. Reduce desperdicios, mejora márgenes y ahorra tiempo.')}
<p className="mt-8 max-w-3xl mx-auto text-lg text-[var(--text-secondary)] sm:text-xl leading-relaxed">
{t('landing:hero.subtitle_option_a', 'La primera IA que conoce tu barrio: colegios cerca, clima local, tu competencia, eventos. Sistema automático cada mañana. Listo a las 6 AM.')}
</p>
{/* CTA Buttons */}
@@ -75,24 +92,48 @@ const LandingPage: React.FC = () => {
</Link>
</div>
{/* Social Proof - New */}
<div className="mt-12 max-w-3xl mx-auto">
<div className="grid md:grid-cols-3 gap-6 text-left">
<div className="flex items-start gap-3 bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm p-4 rounded-xl shadow-sm border border-[var(--border-primary)]">
<CheckCircle2 className="w-5 h-5 text-green-600 dark:text-green-400 mt-0.5 flex-shrink-0" />
<span className="text-sm font-medium text-[var(--text-secondary)]">
<AnimatedCounter value={20} className="inline font-bold" /> panaderías ya ahorran <AnimatedCounter value={1500} prefix="€" className="inline font-bold" />/mes de promedio
</span>
</div>
<div className="flex items-start gap-3 bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm p-4 rounded-xl shadow-sm border border-[var(--border-primary)]">
<Target className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
<span className="text-sm font-medium text-[var(--text-secondary)]">
Predicciones <AnimatedCounter value={92} suffix="%" className="inline font-bold" /> precisas (vs 60% sistemas genéricos)
</span>
</div>
<div className="flex items-start gap-3 bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm p-4 rounded-xl shadow-sm border border-[var(--border-primary)]">
<Clock className="w-5 h-5 text-amber-600 dark:text-amber-400 mt-0.5 flex-shrink-0" />
<span className="text-sm font-medium text-[var(--text-secondary)]">
{t('landing:hero.social_proof.setup', 'Configuración en 15 minutos')}
</span>
</div>
</div>
</div>
{/* Trust Badges */}
<div className="mt-12 flex flex-wrap items-center justify-center gap-x-8 gap-y-4 text-sm">
<div className="flex items-center bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm px-4 py-2 rounded-full shadow-sm border border-[var(--border-primary)]">
<CheckCircle2 className="w-4 h-4 text-amber-600 dark:text-amber-400 mr-2" />
<span className="font-medium text-[var(--text-secondary)]">
{t('landing:hero.trust.card', 'Tarjeta requerida')}
<div className="mt-8 flex flex-wrap items-center justify-center gap-x-8 gap-y-4 text-sm">
<div className="flex items-center">
<CheckCircle2 className="w-4 h-4 text-green-600 dark:text-green-400 mr-2" />
<span className="font-medium text-[var(--text-tertiary)]">
{t('landing:hero.trust.no_cc', '3 meses gratis')}
</span>
</div>
<div className="flex items-center bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm px-4 py-2 rounded-full shadow-sm border border-[var(--border-primary)]">
<div className="flex items-center">
<Clock className="w-4 h-4 text-blue-600 dark:text-blue-400 mr-2" />
<span className="font-medium text-[var(--text-secondary)]">
{t('landing:hero.trust.quick', '3 meses gratis')}
<span className="font-medium text-[var(--text-tertiary)]">
{t('landing:hero.trust.quick', 'Configuración en 15 min')}
</span>
</div>
<div className="flex items-center bg-white/60 dark:bg-gray-800/60 backdrop-blur-sm px-4 py-2 rounded-full shadow-sm border border-[var(--border-primary)]">
<Zap className="w-4 h-4 text-green-600 dark:text-green-400 mr-2" />
<span className="font-medium text-[var(--text-secondary)]">
{t('landing:hero.trust.setup', 'Configuración en 15 min')}
<div className="flex items-center">
<Shield className="w-4 h-4 text-purple-600 dark:text-purple-400 mr-2" />
<span className="font-medium text-[var(--text-tertiary)]">
{t('landing:hero.trust.card', 'Tarjeta requerida')}
</span>
</div>
</div>
@@ -105,10 +146,11 @@ const LandingPage: React.FC = () => {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid md:grid-cols-2 gap-12">
{/* Problems */}
<div>
<h2 className="text-3xl font-bold text-[var(--text-primary)] mb-8">
{t('landing:problems.title', '❌ Los Problemas Que Enfrentas')}
</h2>
<ScrollReveal variant="fadeRight" delay={0.1}>
<div>
<h2 className="text-3xl font-bold text-[var(--text-primary)] mb-8">
{t('landing:problems.title', '❌ Los Problemas Que Enfrentas')}
</h2>
<div className="space-y-6">
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-red-100 dark:bg-red-900/20 rounded-lg flex items-center justify-center flex-shrink-0">
@@ -150,13 +192,15 @@ const LandingPage: React.FC = () => {
</div>
</div>
</div>
</div>
</div>
</ScrollReveal>
{/* Solutions */}
<div>
<h2 className="text-3xl font-bold text-[var(--text-primary)] mb-8">
{t('landing:solutions.title', '✅ La Solución Con IA')}
</h2>
<ScrollReveal variant="fadeLeft" delay={0.2}>
<div>
<h2 className="text-3xl font-bold text-[var(--text-primary)] mb-8">
{t('landing:solutions.title', '✅ La Solución Con IA')}
</h2>
<div className="space-y-6">
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-green-100 dark:bg-green-900/20 rounded-lg flex items-center justify-center flex-shrink-0">
@@ -198,7 +242,8 @@ const LandingPage: React.FC = () => {
</div>
</div>
</div>
</div>
</div>
</ScrollReveal>
</div>
</div>
</section>
@@ -279,7 +324,7 @@ const LandingPage: React.FC = () => {
<div className="mt-6 bg-gradient-to-r from-[var(--color-primary)]/10 to-orange-500/10 rounded-lg p-4 border-l-4 border-[var(--color-primary)]">
<p className="font-bold text-[var(--text-primary)]">
{t('landing:pillar1.accuracy', '🎯 Precisión: 92% (vs 60-70% de sistemas genéricos)')}
🎯 Precisión: <AnimatedCounter value={92} suffix="%" className="inline text-[var(--color-primary)]" /> (vs 60-70% de sistemas genéricos)
</p>
</div>
</div>