Files
bakery-ia/frontend/src/pages/public/FeedbackPage.tsx
2025-10-17 18:14:28 +02:00

436 lines
17 KiB
TypeScript

import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PublicLayout } from '../../components/layout';
import {
MessageSquare,
Heart,
ThumbsUp,
ThumbsDown,
Lightbulb,
AlertTriangle,
Send,
CheckCircle2,
AlertCircle,
Star
} from 'lucide-react';
interface FeedbackCategory {
id: string;
title: string;
description: string;
icon: React.ComponentType<{ className?: string }>;
color: string;
}
const FeedbackPage: React.FC = () => {
const { t } = useTranslation();
const [formState, setFormState] = useState({
name: '',
email: '',
category: 'suggestion' as 'suggestion' | 'bug' | 'feature' | 'praise' | 'complaint',
title: '',
description: '',
rating: 0,
});
const [submitStatus, setSubmitStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const categories: FeedbackCategory[] = [
{
id: 'suggestion',
title: 'Sugerencia',
description: 'Ideas para mejorar el producto',
icon: Lightbulb,
color: 'blue',
},
{
id: 'feature',
title: 'Nueva Funcionalidad',
description: 'Solicita una característica nueva',
icon: Star,
color: 'purple',
},
{
id: 'bug',
title: 'Reportar Bug',
description: 'Algo no funciona como debería',
icon: AlertTriangle,
color: 'red',
},
{
id: 'praise',
title: 'Elogio',
description: '¡Algo te encanta!',
icon: Heart,
color: 'green',
},
{
id: 'complaint',
title: 'Queja',
description: 'Algo te molesta o decepciona',
icon: ThumbsDown,
color: 'amber',
},
];
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
setFormState({
...formState,
[e.target.name]: e.target.value,
});
};
const handleRatingChange = (rating: number) => {
setFormState({
...formState,
rating,
});
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSubmitStatus('loading');
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1500));
// In production, this would be an actual API call
console.log('Feedback submitted:', formState);
setSubmitStatus('success');
setTimeout(() => {
setSubmitStatus('idle');
setFormState({
name: '',
email: '',
category: 'suggestion',
title: '',
description: '',
rating: 0,
});
}, 3000);
};
const getCategoryColor = (color: string) => {
const colors: Record<string, string> = {
blue: 'from-blue-500/10 to-blue-600/10 border-blue-500/20',
purple: 'from-purple-500/10 to-purple-600/10 border-purple-500/20',
red: 'from-red-500/10 to-red-600/10 border-red-500/20',
green: 'from-green-500/10 to-green-600/10 border-green-500/20',
amber: 'from-amber-500/10 to-amber-600/10 border-amber-500/20',
};
return colors[color] || colors.blue;
};
const getCategoryIconColor = (color: string) => {
const colors: Record<string, string> = {
blue: 'text-blue-600',
purple: 'text-purple-600',
red: 'text-red-600',
green: 'text-green-600',
amber: 'text-amber-600',
};
return colors[color] || colors.blue;
};
return (
<PublicLayout
variant="default"
contentPadding="default"
headerProps={{
showThemeToggle: true,
showAuthButtons: true,
showLanguageSelector: true,
variant: 'default',
}}
>
{/* Hero Section */}
<section className="bg-gradient-to-br from-[var(--bg-primary)] via-[var(--bg-secondary)] to-[var(--color-primary)]/5 py-20">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center max-w-4xl mx-auto">
<div className="inline-flex items-center gap-2 bg-[var(--color-primary)]/10 text-[var(--color-primary)] px-4 py-2 rounded-full text-sm font-medium mb-6">
<MessageSquare className="w-4 h-4" />
<span>Tu Opinión Importa</span>
</div>
<h1 className="text-4xl lg:text-6xl font-extrabold text-[var(--text-primary)] mb-6">
Ayúdanos a Mejorar
<span className="block text-[var(--color-primary)]">Panadería IA</span>
</h1>
<p className="text-xl text-[var(--text-secondary)] leading-relaxed mb-8">
Tu feedback es fundamental para construir el mejor producto para panaderías artesanales
</p>
</div>
</div>
</section>
{/* Why Feedback Matters */}
<section className="py-20 bg-[var(--bg-primary)]">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl lg:text-4xl font-extrabold text-[var(--text-primary)] mb-4">
¿Por Qué Tu Feedback Es Importante?
</h2>
<p className="text-xl text-[var(--text-secondary)]">
Estamos construyendo esto juntos
</p>
</div>
<div className="grid md:grid-cols-3 gap-6 mb-16">
<div className="bg-[var(--bg-secondary)] rounded-2xl p-6 border border-[var(--border-primary)] text-center">
<ThumbsUp className="w-12 h-12 text-[var(--color-primary)] mx-auto mb-4" />
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
Priorizamos Tu Feedback
</h3>
<p className="text-sm text-[var(--text-secondary)]">
Cada sugerencia es revisada y considerada para el roadmap de producto
</p>
</div>
<div className="bg-[var(--bg-secondary)] rounded-2xl p-6 border border-[var(--border-primary)] text-center">
<Lightbulb className="w-12 h-12 text-[var(--color-primary)] mx-auto mb-4" />
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
Tus Ideas Nos Inspiran
</h3>
<p className="text-sm text-[var(--text-secondary)]">
Las mejores funcionalidades vienen directamente de nuestros usuarios
</p>
</div>
<div className="bg-[var(--bg-secondary)] rounded-2xl p-6 border border-[var(--border-primary)] text-center">
<Heart className="w-12 h-12 text-[var(--color-primary)] mx-auto mb-4" />
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
Comunidad Activa
</h3>
<p className="text-sm text-[var(--text-secondary)]">
Contribuyes a crear una herramienta que toda la comunidad panadera disfrutará
</p>
</div>
</div>
</div>
</section>
{/* Feedback Form */}
<section className="py-20 bg-[var(--bg-secondary)]">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl lg:text-4xl font-extrabold text-[var(--text-primary)] mb-4">
Comparte Tu Feedback
</h2>
<p className="text-xl text-[var(--text-secondary)]">
Queremos escucharte
</p>
</div>
{/* Category Selection */}
<div className="mb-8">
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-4 text-center">
¿Qué tipo de feedback quieres compartir?
</h3>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
{categories.map((category) => {
const CategoryIcon = category.icon;
const isSelected = formState.category === category.id;
return (
<button
key={category.id}
type="button"
onClick={() => setFormState({ ...formState, category: category.id as any })}
className={`bg-gradient-to-br ${getCategoryColor(category.color)} rounded-xl p-6 border-2 transition-all text-left ${
isSelected
? 'border-[var(--color-primary)] shadow-lg'
: 'border-transparent hover:border-[var(--color-primary)]/30'
}`}
>
<CategoryIcon className={`w-8 h-8 ${getCategoryIconColor(category.color)} mb-3`} />
<h4 className="font-bold text-[var(--text-primary)] mb-1">{category.title}</h4>
<p className="text-xs text-[var(--text-secondary)]">{category.description}</p>
</button>
);
})}
</div>
</div>
<form onSubmit={handleSubmit} className="bg-[var(--bg-primary)] rounded-2xl p-8 border border-[var(--border-primary)]">
{/* Success/Error Messages */}
{submitStatus === 'success' && (
<div className="mb-6 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-xl flex items-center gap-3">
<CheckCircle2 className="w-5 h-5 text-green-600 flex-shrink-0" />
<p className="text-sm text-green-800 dark:text-green-200">
<strong>¡Gracias por tu feedback!</strong> Lo revisaremos pronto.
</p>
</div>
)}
{submitStatus === 'error' && (
<div className="mb-6 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl flex items-center gap-3">
<AlertCircle className="w-5 h-5 text-red-600 flex-shrink-0" />
<p className="text-sm text-red-800 dark:text-red-200">
<strong>Error al enviar.</strong> Por favor, inténtalo de nuevo.
</p>
</div>
)}
<div className="grid md:grid-cols-2 gap-6">
{/* Name */}
<div>
<label htmlFor="name" className="block text-sm font-medium text-[var(--text-primary)] mb-2">
Tu Nombre <span className="text-red-500">*</span>
</label>
<input
type="text"
id="name"
name="name"
value={formState.name}
onChange={handleChange}
required
className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors"
placeholder="Tu nombre"
/>
</div>
{/* Email */}
<div>
<label htmlFor="email" className="block text-sm font-medium text-[var(--text-primary)] mb-2">
Email <span className="text-red-500">*</span>
</label>
<input
type="email"
id="email"
name="email"
value={formState.email}
onChange={handleChange}
required
className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors"
placeholder="tu@email.com"
/>
</div>
</div>
{/* Rating */}
{formState.category === 'praise' && (
<div className="mt-6">
<label className="block text-sm font-medium text-[var(--text-primary)] mb-3">
¿Cómo calificarías tu experiencia? <span className="text-red-500">*</span>
</label>
<div className="flex gap-2">
{[1, 2, 3, 4, 5].map((rating) => (
<button
key={rating}
type="button"
onClick={() => handleRatingChange(rating)}
className="transition-transform hover:scale-110"
>
<Star
className={`w-10 h-10 ${
rating <= formState.rating
? 'fill-yellow-500 text-yellow-500'
: 'text-[var(--border-primary)]'
}`}
/>
</button>
))}
</div>
</div>
)}
{/* Title */}
<div className="mt-6">
<label htmlFor="title" className="block text-sm font-medium text-[var(--text-primary)] mb-2">
Título <span className="text-red-500">*</span>
</label>
<input
type="text"
id="title"
name="title"
value={formState.title}
onChange={handleChange}
required
className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors"
placeholder="Resumen en una línea"
/>
</div>
{/* Description */}
<div className="mt-6">
<label htmlFor="description" className="block text-sm font-medium text-[var(--text-primary)] mb-2">
Descripción Detallada <span className="text-red-500">*</span>
</label>
<textarea
id="description"
name="description"
value={formState.description}
onChange={handleChange}
required
rows={6}
className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors resize-none"
placeholder={
formState.category === 'bug'
? 'Describe el problema: ¿qué esperabas que pasara? ¿qué pasó en su lugar? ¿cómo podemos reproducirlo?'
: formState.category === 'feature'
? 'Describe la funcionalidad que te gustaría ver: ¿qué problema resolvería? ¿cómo lo imaginas?'
: 'Cuéntanos más sobre tu feedback...'
}
/>
</div>
{/* Submit Button */}
<div className="mt-8">
<button
type="submit"
disabled={submitStatus === 'loading'}
className="w-full flex items-center justify-center gap-2 px-8 py-4 bg-[var(--color-primary)] text-white rounded-xl font-bold hover:shadow-xl transition-all hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100"
>
{submitStatus === 'loading' ? (
<>
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />
<span>Enviando...</span>
</>
) : (
<>
<Send className="w-5 h-5" />
<span>Enviar Feedback</span>
</>
)}
</button>
</div>
<p className="text-xs text-[var(--text-tertiary)] text-center mt-4">
Tu feedback nos ayuda a mejorar. ¡Gracias por tomarte el tiempo!
</p>
</form>
</div>
</section>
{/* Other Ways to Connect */}
<section className="py-20 bg-[var(--bg-primary)]">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="bg-gradient-to-br from-[var(--color-primary)]/10 to-orange-600/10 rounded-2xl p-8 border border-[var(--color-primary)]/20 text-center">
<h3 className="text-2xl font-bold text-[var(--text-primary)] mb-4">
¿Prefieres Hablar Directamente?
</h3>
<p className="text-[var(--text-secondary)] mb-6">
Estamos disponibles por múltiples canales
</p>
<div className="flex flex-wrap justify-center gap-4">
<a
href="/help/support"
className="inline-flex items-center gap-2 px-6 py-3 bg-[var(--color-primary)] text-white rounded-xl font-bold hover:shadow-xl transition-all hover:scale-105"
>
<MessageSquare className="w-5 h-5" />
<span>Contactar Soporte</span>
</a>
<a
href="/help"
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-[var(--border-primary)] text-[var(--text-primary)] rounded-xl font-medium hover:border-[var(--color-primary)] transition-all"
>
Centro de Ayuda
</a>
</div>
</div>
</div>
</section>
</PublicLayout>
);
};
export default FeedbackPage;