Files
clube67.com/frontend/app/benefits/page.tsx
T

139 lines
7.5 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import DashboardLayout from '@/components/layout/DashboardLayout';
import { api } from '@/lib/api';
import { useAuth } from '@/lib/auth';
export default function BenefitsPage() {
const { user } = useAuth();
const [benefits, setBenefits] = useState<any[]>([]);
const [categories, setCategories] = useState<any[]>([]);
const [search, setSearch] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
api.getCategories().then(d => setCategories(d.categories || [])).catch(console.error);
loadBenefits();
}, []);
const loadBenefits = async (catId?: string) => {
setLoading(true);
try {
const params = new URLSearchParams();
if (catId) params.set('category', catId);
if (search) params.set('search', search);
const d = await api.getBenefits(params.toString());
setBenefits(d.benefits || []);
} catch (e) { console.error(e); }
setLoading(false);
};
const handleFilter = (catId: string) => {
setSelectedCategory(catId);
loadBenefits(catId);
};
const handleRedeem = async (id: number) => {
try {
await api.redeemBenefit(id);
alert('Benefício resgatado com sucesso! Verifique seu e-mail.');
} catch (err: any) {
alert(err.message || 'Erro ao resgatar');
}
};
const handleFavorite = async (id: number) => {
try {
await api.addFavorite(id);
alert('Adicionado aos favoritos!');
} catch { }
};
return (
<DashboardLayout>
<div className="space-y-8">
<div>
<h1 className="text-3xl font-bold">🎁 <span className="gradient-text">Benefícios</span></h1>
<p className="text-dark-400 mt-1">Explore e resgate benefícios exclusivos dos nossos parceiros.</p>
</div>
{/* Search + Filter */}
<div className="flex flex-col md:flex-row gap-4">
<div className="flex-1">
<input type="text" value={search} onChange={e => setSearch(e.target.value)}
onKeyDown={e => e.key === 'Enter' && loadBenefits(selectedCategory)}
placeholder="Buscar benefícios..."
className="w-full px-4 py-3 bg-dark-900 border border-dark-700 rounded-xl text-white focus:border-brand-500 outline-none" />
</div>
<div className="flex gap-2 overflow-x-auto pb-2">
<button onClick={() => handleFilter('')}
className={`px-4 py-2 rounded-xl text-sm whitespace-nowrap transition-all ${!selectedCategory ? 'bg-brand-600 text-white' : 'glass text-dark-400 hover:text-white'
}`}>Todos</button>
{categories.map(c => (
<button key={c.id} onClick={() => handleFilter(c.id.toString())}
className={`px-4 py-2 rounded-xl text-sm whitespace-nowrap transition-all ${selectedCategory === c.id.toString() ? 'bg-brand-600 text-white' : 'glass text-dark-400 hover:text-white'
}`}>
{c.icon} {c.name}
</button>
))}
</div>
</div>
{/* Benefits Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
{loading ? [1, 2, 3, 4, 5, 6].map(i => <div key={i} className="skeleton h-56 rounded-2xl" />) :
benefits.length === 0 ? (
<div className="col-span-full text-center py-16 glass rounded-2xl">
<div className="text-5xl mb-4">🔍</div>
<p className="text-xl font-semibold mb-2">Nenhum benefício encontrado</p>
<p className="text-dark-400">Tente ajustar os filtros de busca.</p>
</div>
) :
benefits.map((b, i) => (
<motion.div key={b.id} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: i * 0.05 }}
className="glass rounded-2xl overflow-hidden hover:bg-white/5 transition-all group">
{/* Gradient Header */}
<div className="h-2" style={{ background: `linear-gradient(to right, ${b.gradient_from || '#3B82F6'}, ${b.gradient_to || '#8B5CF6'})` }} />
<div className="p-5">
<div className="flex items-start justify-between mb-3">
<div>
<h3 className="font-bold text-lg group-hover:text-brand-400 transition-colors">{b.title}</h3>
<p className="text-xs text-dark-500 mt-1">{b.partner_name || 'Parceiro'}</p>
</div>
{b.discount_percent && (
<div className="bg-green-500/15 text-green-400 text-sm font-bold px-3 py-1 rounded-lg">
-{b.discount_percent}%
</div>
)}
</div>
<p className="text-sm text-dark-400 mb-4 line-clamp-2">{b.description}</p>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
{b.badge && <span className="text-xs px-2 py-1 rounded-lg bg-purple-500/15 text-purple-400">{b.badge}</span>}
{b.is_global && <span className="text-xs px-2 py-1 rounded-lg bg-brand-500/15 text-brand-400">🌐 Global</span>}
</div>
<div className="flex gap-2">
<button onClick={() => handleFavorite(b.id)}
className="p-2 rounded-lg hover:bg-yellow-500/15 text-dark-400 hover:text-yellow-400 transition-all" title="Favoritar">
</button>
<button onClick={() => handleRedeem(b.id)}
className="px-4 py-2 bg-brand-600 hover:bg-brand-500 rounded-lg text-sm font-semibold transition-all">
Resgatar
</button>
</div>
</div>
</div>
</motion.div>
))}
</div>
</div>
</DashboardLayout>
);
}