feat: overhaul profile page UI with refreshed glassmorphism header, updated layout, and enhanced navigation tabs
This commit is contained in:
@@ -106,18 +106,18 @@ export default function Profile() {
|
||||
|
||||
if (!authId) {
|
||||
return (
|
||||
<div className="text-center py-16">
|
||||
<div className="w-16 h-16 bg-indigo-100 rounded-2xl flex items-center justify-center mx-auto mb-4">
|
||||
<User size={28} className="text-indigo-600" />
|
||||
<div className="text-center py-20">
|
||||
<div className="w-20 h-20 bg-indigo-50 rounded-3xl flex items-center justify-center mx-auto mb-6 shadow-inner">
|
||||
<User size={32} className="text-indigo-600" />
|
||||
</div>
|
||||
<p className="text-slate-700 font-semibold mb-1">Sessão não encontrada</p>
|
||||
<p className="text-slate-500 text-sm mb-4">Faz login para ver o teu perfil.</p>
|
||||
<h2 className="text-2xl font-black text-slate-900 uppercase italic tracking-tighter mb-2">Sessão expirada</h2>
|
||||
<p className="text-slate-500 font-medium italic mb-8">Faz login para aceder ao teu cofre pessoal.</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/login', { replace: true })}
|
||||
className="px-5 py-2 bg-indigo-600 text-white text-sm font-semibold rounded-xl hover:bg-slate-900 transition-colors"
|
||||
className="px-8 py-3 bg-slate-900 text-indigo-400 text-xs font-black rounded-2xl hover:bg-indigo-600 hover:text-white transition-all uppercase tracking-widest shadow-xl active:scale-95"
|
||||
>
|
||||
Ir para login
|
||||
Iniciar Sessão
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
@@ -137,123 +137,99 @@ export default function Profile() {
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="max-w-4xl mx-auto space-y-6 sm:space-y-12 pb-12 sm:pb-20">
|
||||
{/* Cabeçalho do Perfil */}
|
||||
<section className="relative overflow-hidden rounded-2xl sm:rounded-[3rem] obsidian-gradient text-white p-4 sm:p-8 md:p-12 shadow-2xl border border-white/5">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-indigo-500/10 rounded-full blur-[80px] -translate-y-1/2 translate-x-1/2" />
|
||||
<div className="relative z-10 flex flex-col md:flex-row items-center gap-6 md:gap-8 md:text-left text-center">
|
||||
<div className="relative group">
|
||||
<div className="absolute inset-0 bg-indigo-500 blur-2xl opacity-20 group-hover:opacity-40 transition-opacity" />
|
||||
<div className="w-16 h-16 sm:w-24 sm:h-24 bg-white/10 backdrop-blur-xl border-2 border-white/20 rounded-xl sm:rounded-[2rem] flex items-center justify-center text-indigo-400 shadow-2xl relative z-10 transition-transform duration-500 hover:rotate-6">
|
||||
<User size={30} className="sm:hidden" />
|
||||
<User size={48} className="hidden sm:block" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2 sm:space-y-3">
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 bg-white/5 border border-white/10 rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-[0.2em] text-indigo-400">
|
||||
<Star size={10} fill="currentColor" />
|
||||
<span>Utilizador Registado</span>
|
||||
<div className="max-w-4xl mx-auto space-y-8 sm:space-y-12 pb-20">
|
||||
{/* Profile Glass Header */}
|
||||
<section className="relative group">
|
||||
<div className="absolute -inset-1 bg-gradient-to-r from-indigo-500 to-purple-600 rounded-[2.5rem] blur opacity-10 group-hover:opacity-20 transition duration-1000"></div>
|
||||
<div className="relative overflow-hidden rounded-[2.5rem] obsidian-gradient border border-white/10 shadow-2xl">
|
||||
{/* Background elements */}
|
||||
<div className="absolute top-0 right-0 w-80 h-80 bg-indigo-500/20 rounded-full blur-[100px] -translate-y-1/2 translate-x-1/2" />
|
||||
<div className="absolute bottom-0 left-0 w-64 h-64 bg-purple-500/10 rounded-full blur-[80px] translate-y-1/2 -translate-x-1/2" />
|
||||
|
||||
<div className="relative z-10 p-6 sm:p-10 md:p-14 flex flex-col md:flex-row items-center gap-8 md:text-left text-center">
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 bg-indigo-500 rounded-[2rem] blur-2xl opacity-20 animate-pulse" />
|
||||
<div className="w-20 h-20 sm:w-28 sm:h-28 bg-white/10 backdrop-blur-2xl border-2 border-white/20 rounded-[2rem] flex items-center justify-center text-indigo-400 shadow-2xl relative z-10 transition-transform duration-700 hover:scale-105 hover:rotate-3">
|
||||
<User size={40} className="sm:hidden" />
|
||||
<User size={56} className="hidden sm:block" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3 sm:space-y-4">
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 bg-indigo-500/10 border border-indigo-500/20 rounded-full text-[10px] font-black uppercase tracking-[0.2em] text-indigo-400">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-ping" />
|
||||
<span>Membro Verificado</span>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h1 className="text-3xl sm:text-5xl md:text-6xl font-black text-white tracking-tighter uppercase italic leading-[0.85]">
|
||||
{displayName}
|
||||
</h1>
|
||||
<p className="text-slate-400 font-bold italic tracking-wide text-sm sm:text-base">{authEmail}</p>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-xl sm:text-4xl md:text-5xl font-black tracking-tighter uppercase italic leading-[0.9]">
|
||||
{displayName}
|
||||
</h1>
|
||||
<p className="text-sm sm:text-lg text-slate-400 font-medium italic">{authEmail}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 🔔 Notificações */}
|
||||
{myNotifications.filter(n => !n.read).length > 0 && (
|
||||
<section className="space-y-4">
|
||||
<div className="flex items-center gap-2 px-2 text-rose-600">
|
||||
<Bell size={18} className="fill-rose-100" />
|
||||
<h2 className="text-sm font-black uppercase tracking-[0.2em]">Notificações</h2>
|
||||
</div>
|
||||
<div className="grid gap-3">
|
||||
{myNotifications.filter(n => !n.read).map(n => (
|
||||
<div key={n.id} className="p-4 bg-white border border-rose-100 shadow-md rounded-2xl flex items-center justify-between gap-4">
|
||||
<div className="flex-1">
|
||||
<p className="text-slate-800 text-sm font-semibold">{n.message}</p>
|
||||
<p className="text-xs text-slate-400 mt-1">{new Date(n.createdAt).toLocaleString('pt-PT')}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => markNotificationRead(n.id)}
|
||||
className="px-3 py-1 bg-slate-100 hover:bg-slate-200 text-slate-600 font-bold text-[10px] uppercase tracking-widest rounded-lg transition-colors"
|
||||
>
|
||||
Marcar Lida
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Navegação por Tabs no Perfil */}
|
||||
<div className="w-full max-w-[100vw] overflow-hidden px-1 sm:px-0">
|
||||
<div className="flex gap-1.5 p-1 bg-white/50 backdrop-blur-md rounded-xl sm:rounded-2xl border border-white/20 shadow-sm overflow-x-auto scrollbar-hide">
|
||||
{/* Floating Navigation Tabs */}
|
||||
<div className="sticky top-4 z-40 px-2">
|
||||
<div className="w-full max-w-fit mx-auto bg-white/90 backdrop-blur-2xl p-1.5 rounded-2xl sm:rounded-[2rem] border border-white/50 shadow-2xl shadow-indigo-500/5 flex items-center gap-1.5 overflow-x-auto scrollbar-hide flex-nowrap">
|
||||
{[
|
||||
{ id: 'favoritos', label: 'Favoritos', icon: Heart, count: favoriteShops.length },
|
||||
{ id: 'agenda', label: 'Minha Agenda', icon: Calendar, count: myAppointments.length },
|
||||
{ id: 'pedidos', label: 'Pedidos', icon: ShoppingBag, count: myOrders.length },
|
||||
{ id: 'favoritos', label: 'Favoritos', icon: Heart, color: 'text-rose-500' },
|
||||
{ id: 'agenda', label: 'Agenda', icon: Calendar, color: 'text-indigo-500' },
|
||||
{ id: 'pedidos', label: 'Pedidos', icon: ShoppingBag, color: 'text-emerald-500' },
|
||||
].map((t) => (
|
||||
<button
|
||||
key={t.id}
|
||||
onClick={() => setActiveTab(t.id as any)}
|
||||
className={`flex items-center gap-2 px-4 py-2.5 rounded-lg sm:rounded-xl whitespace-nowrap transition-all shrink-0 ${
|
||||
className={`flex items-center gap-2.5 px-5 py-3 rounded-xl sm:rounded-2xl whitespace-nowrap transition-all duration-500 shrink-0 ${
|
||||
activeTab === t.id
|
||||
? 'bg-slate-900 text-indigo-400 shadow-lg scale-[1.02]'
|
||||
: 'text-slate-500 hover:bg-slate-100'
|
||||
? 'bg-slate-950 text-white shadow-xl scale-100'
|
||||
: 'text-slate-500 hover:bg-slate-100/50 hover:text-slate-900'
|
||||
}`}
|
||||
>
|
||||
<t.icon size={14} className={activeTab === t.id ? 'fill-current' : ''} />
|
||||
<span className="text-[10px] sm:text-xs font-black uppercase tracking-widest">{t.label}</span>
|
||||
{t.count > 0 && (
|
||||
<span className={`ml-1 flex items-center justify-center min-w-[18px] h-[18px] rounded-full text-[9px] font-bold border ${
|
||||
activeTab === t.id ? 'bg-indigo-500 text-white border-indigo-400' : 'bg-slate-100 text-slate-500 border-slate-200'
|
||||
}`}>
|
||||
{t.count}
|
||||
</span>
|
||||
)}
|
||||
<t.icon size={16} className={activeTab === t.id ? t.color : 'opacity-40'} fill={activeTab === t.id ? 'currentColor' : 'none'} />
|
||||
<span className="text-[11px] sm:text-xs font-black uppercase tracking-widest">{t.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
{/* Tab Content with Animation */}
|
||||
<div className="min-h-[400px]">
|
||||
{activeTab === 'favoritos' && (
|
||||
<section className="space-y-6">
|
||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-8 duration-700">
|
||||
<div className="flex items-center justify-between px-4">
|
||||
<h2 className="text-xs font-black text-slate-400 uppercase tracking-[0.3em]">Cofre de Favoritos</h2>
|
||||
<span className="px-2 py-1 bg-slate-100 rounded-lg text-[10px] font-black text-slate-500">{favoriteShops.length} ESPAÇOS</span>
|
||||
</div>
|
||||
{!favoriteShops.length ? (
|
||||
<Card className="p-12 sm:p-16 text-center border-none glass-card rounded-[2.5rem] sm:rounded-[3rem] shadow-xl">
|
||||
<Heart size={48} className="mx-auto text-slate-100 mb-6" />
|
||||
<h3 className="text-lg sm:text-xl font-black text-slate-900 uppercase italic tracking-tight">Sem Favoritos</h3>
|
||||
<p className="text-slate-400 font-medium italic mt-2 text-sm">Ainda não escolheste os teus espaços preferidos.</p>
|
||||
<Button asChild className="mt-8 h-10 sm:h-12 px-8 bg-slate-900 text-indigo-400 font-black rounded-xl sm:rounded-2xl uppercase tracking-widest text-[10px] italic">
|
||||
<Link to="/explorar">Explorar Barbearias</Link>
|
||||
</Button>
|
||||
</Card>
|
||||
<div className="py-20 text-center bg-white/50 rounded-[3rem] border border-white/50 border-dashed">
|
||||
<Heart size={48} className="mx-auto text-slate-200 mb-6" />
|
||||
<p className="text-slate-400 font-bold italic">Nenhuma barbearia favorita ainda.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6 px-2 sm:px-0">
|
||||
{favoriteShops.map((shop) => (
|
||||
<Link key={shop.id} to={`/barbearia/${shop.id}`}>
|
||||
<Card className="p-1.5 sm:p-2 border-none glass-card rounded-2xl sm:rounded-[2rem] shadow-lg shadow-slate-200/50 hover:-translate-y-1 transition-all duration-300 group">
|
||||
<div className="flex items-center gap-3 sm:gap-4 p-3 sm:p-4">
|
||||
<div className="w-14 h-14 sm:w-16 sm:h-16 rounded-xl sm:rounded-2xl overflow-hidden border-2 border-slate-50 shadow-inner group-hover:border-indigo-200 transition-colors">
|
||||
<Link key={shop.id} to={`/barbearia/${shop.id}`} className="group">
|
||||
<Card className="p-3 border-none bg-white/70 backdrop-blur-sm rounded-[2.5rem] shadow-xl shadow-slate-200/40 hover:shadow-2xl hover:shadow-indigo-500/10 transition-all duration-500 border border-white/50">
|
||||
<div className="flex items-center gap-5 p-2">
|
||||
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-3xl overflow-hidden border-2 border-white shadow-xl group-hover:rotate-3 transition-transform duration-500">
|
||||
{shop.imageUrl ? (
|
||||
<img src={shop.imageUrl} alt={shop.name} className="w-full h-full object-cover" />
|
||||
) : (
|
||||
<div className="w-full h-full bg-slate-100 flex items-center justify-center text-slate-300">
|
||||
<User size={24} />
|
||||
<div className="w-full h-full bg-slate-50 flex items-center justify-center text-slate-200">
|
||||
<User size={28} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-black text-sm sm:text-base text-slate-900 uppercase italic tracking-tight group-hover:text-indigo-600 transition-colors truncate">{shop.name}</p>
|
||||
<div className="flex items-center gap-3 mt-1">
|
||||
<div className="flex items-center gap-1 text-[9px] sm:text-[10px] font-black text-indigo-600 uppercase tracking-widest">
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<h3 className="font-black text-base sm:text-lg text-slate-900 uppercase italic tracking-tighter group-hover:text-indigo-600 transition-colors truncate">{shop.name}</h3>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 bg-indigo-50 rounded-lg text-[10px] font-black text-indigo-600 uppercase tracking-widest">
|
||||
<Star size={10} className="fill-indigo-500" />
|
||||
{shop.rating.toFixed(1)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1 text-[9px] sm:text-[10px] font-black text-slate-400 uppercase tracking-widest truncate">
|
||||
<div className="flex items-center gap-1.5 text-[10px] font-bold text-slate-400 uppercase tracking-tight truncate">
|
||||
<MapPin size={10} />
|
||||
{shop.address.split(',')[0]}
|
||||
</div>
|
||||
@@ -265,65 +241,71 @@ export default function Profile() {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'agenda' && (
|
||||
<section className="space-y-6">
|
||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-8 duration-700">
|
||||
<div className="flex items-center justify-between px-4">
|
||||
<h2 className="text-xs font-black text-slate-400 uppercase tracking-[0.3em]">Minha Agenda</h2>
|
||||
<span className="px-2 py-1 bg-slate-100 rounded-lg text-[10px] font-black text-slate-500">{myAppointments.length} RESERVAS</span>
|
||||
</div>
|
||||
{!myAppointments.length ? (
|
||||
<Card className="p-16 text-center border-none glass-card rounded-[2.5rem] sm:rounded-[3rem] shadow-xl">
|
||||
<Calendar size={48} className="mx-auto text-slate-100 mb-6" />
|
||||
<h3 className="text-lg sm:text-xl font-black text-slate-900 uppercase italic tracking-tight">Sem Reservas</h3>
|
||||
<p className="text-slate-400 font-medium italic mt-2 text-sm">Sua jornada de estilo ainda não começou.</p>
|
||||
<Button asChild className="mt-8 h-10 sm:h-12 px-8 bg-slate-900 text-indigo-400 font-black rounded-xl sm:rounded-2xl uppercase tracking-widest text-[10px] italic">
|
||||
<Link to="/explorar">Agendar Agora</Link>
|
||||
</Button>
|
||||
</Card>
|
||||
<div className="py-20 text-center bg-white/50 rounded-[3rem] border border-white/50 border-dashed">
|
||||
<Calendar size={48} className="mx-auto text-slate-200 mb-6" />
|
||||
<p className="text-slate-400 font-bold italic">Sem agendamentos futuros.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid gap-4 sm:gap-6">
|
||||
<div className="grid gap-6 px-2 sm:px-0">
|
||||
{myAppointments.map((a) => {
|
||||
const shop = shops.find((s) => s.id === a.shopId)
|
||||
const service = shop?.services.find((s) => s.id === a.serviceId)
|
||||
const canReview = a.status === 'concluido' && !reviewedAppointments.has(a.id)
|
||||
|
||||
return (
|
||||
<Card key={a.id} className="p-1 sm:p-1.5 border-none glass-card rounded-2xl sm:rounded-[2.5rem] shadow-lg shadow-slate-200/50">
|
||||
<div className="p-4 sm:p-6 space-y-3 sm:space-y-4">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="space-y-1">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3">
|
||||
<h3 className="font-black text-lg sm:text-xl text-slate-900 uppercase italic tracking-tighter truncate max-w-[200px]">{shop?.name}</h3>
|
||||
<div className={`w-fit px-2 py-0.5 rounded-full text-[8px] font-black uppercase tracking-widest bg-${statusColor[a.status]}-100 text-${statusColor[a.status]}-700`}>
|
||||
<Card key={a.id} className="overflow-hidden border-none bg-white shadow-xl shadow-slate-200/50 rounded-[2.5rem]">
|
||||
<div className="p-6 sm:p-8 space-y-6">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<h3 className="font-black text-xl sm:text-2xl text-slate-950 uppercase italic tracking-tighter">{shop?.name}</h3>
|
||||
<Badge className={`w-fit bg-${statusColor[a.status]}-50 text-${statusColor[a.status]}-600 border-${statusColor[a.status]}-100 font-black uppercase text-[8px] tracking-[0.2em] py-1 px-3`}>
|
||||
{statusLabel[a.status]}
|
||||
</div>
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-slate-400 font-black text-[10px] uppercase tracking-widest bg-slate-50 w-fit px-3 py-1.5 rounded-xl">
|
||||
<Clock size={12} className="text-indigo-500" />
|
||||
{a.date}
|
||||
</div>
|
||||
<p className="text-[10px] sm:text-xs font-black text-slate-400 uppercase tracking-[0.2em]">{a.date}</p>
|
||||
</div>
|
||||
<div className="text-xl sm:text-2xl font-black text-slate-900 tracking-tighter italic">
|
||||
<div className="text-2xl sm:text-3xl font-black text-slate-950 tracking-tighter bg-indigo-50/50 px-4 py-2 rounded-2xl border border-indigo-100">
|
||||
{currency(a.total)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between pt-4 border-t border-slate-50 gap-3">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between pt-6 border-t border-slate-100 gap-4">
|
||||
{service && (
|
||||
<div className="flex items-center gap-2 text-[9px] sm:text-[10px] font-black text-slate-500 uppercase tracking-widest">
|
||||
<Clock size={12} className="text-indigo-600" />
|
||||
{service.name} · {service.duration} MIN
|
||||
<div className="flex items-center gap-3 text-[10px] sm:text-xs font-black text-slate-600 uppercase tracking-widest">
|
||||
<div className="p-2 bg-slate-100 rounded-lg">
|
||||
<Scissors size={14} className="text-indigo-600" />
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-slate-400 text-[9px] mb-0.5">SERVIÇO</span>
|
||||
<span>{service.name} · {service.duration} MIN</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{canReview && (
|
||||
{canReview ? (
|
||||
<button
|
||||
onClick={() => setReviewTarget({ appointmentId: a.id, shopId: a.shopId, shopName: shop?.name ?? 'Barbearia' })}
|
||||
className="flex items-center justify-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-slate-900 text-white hover:text-indigo-400 rounded-lg sm:rounded-xl transition-all duration-300 transform active:scale-95 shadow-lg shadow-indigo-500/20"
|
||||
className="flex items-center justify-center gap-2 px-6 py-3 bg-slate-950 hover:bg-indigo-600 text-white rounded-2xl transition-all duration-300 transform active:scale-95 shadow-xl shadow-slate-900/10"
|
||||
>
|
||||
<Star size={12} className="fill-current" />
|
||||
<span className="text-[9px] sm:text-[10px] font-black uppercase tracking-widest">Avaliar Atendimento</span>
|
||||
<Star size={12} className="fill-current text-indigo-400" />
|
||||
<span className="text-[10px] font-black uppercase tracking-widest">Avaliar Agora</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{a.status === 'concluido' && reviewedAppointments.has(a.id) && (
|
||||
<div className="flex items-center gap-1 text-[9px] sm:text-[10px] font-black text-green-600 uppercase tracking-widest">
|
||||
) : a.status === 'concluido' && (
|
||||
<div className="flex items-center gap-2 px-4 py-2 bg-green-50 text-green-600 rounded-xl text-[10px] font-black uppercase tracking-widest">
|
||||
<CheckCircle2 size={12} />
|
||||
Avaliado
|
||||
</div>
|
||||
@@ -335,35 +317,52 @@ export default function Profile() {
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'pedidos' && (
|
||||
<section className="space-y-6">
|
||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-8 duration-700">
|
||||
<div className="flex items-center justify-between px-4">
|
||||
<h2 className="text-xs font-black text-slate-400 uppercase tracking-[0.3em]">Meus Pedidos</h2>
|
||||
<span className="px-2 py-1 bg-slate-100 rounded-lg text-[10px] font-black text-slate-500">{myOrders.length} ITEMS</span>
|
||||
</div>
|
||||
{!myOrders.length ? (
|
||||
<Card className="p-12 sm:p-16 text-center border-none glass-card rounded-[2.5rem] sm:rounded-[3rem] shadow-xl">
|
||||
<ShoppingBag size={48} className="mx-auto text-slate-100 mb-6" />
|
||||
<p className="text-slate-400 font-medium italic text-sm">Sem encomendas efetuadas.</p>
|
||||
</Card>
|
||||
<div className="py-20 text-center bg-white/50 rounded-[3rem] border border-white/50 border-dashed">
|
||||
<ShoppingBag size={48} className="mx-auto text-slate-200 mb-6" />
|
||||
<p className="text-slate-400 font-bold italic">Ainda não compraste produtos.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6 px-2 sm:px-0">
|
||||
{myOrders.map((o) => {
|
||||
const shop = shops.find((s) => s.id === o.shopId)
|
||||
return (
|
||||
<Card key={o.id} className="p-1 sm:p-1.5 border-none glass-card rounded-2xl sm:rounded-[2rem] shadow-lg shadow-slate-200/50">
|
||||
<div className="p-4 sm:p-5 space-y-3">
|
||||
<Card key={o.id} className="p-5 border-none bg-white rounded-[2.5rem] shadow-xl shadow-slate-200/50 group overflow-hidden relative">
|
||||
<div className={`absolute top-0 right-0 w-24 h-24 bg-${statusColor[o.status]}-500/5 rounded-full blur-3xl`} />
|
||||
<div className="space-y-4 relative z-10">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="font-black text-sm sm:text-base text-slate-900 uppercase italic tracking-tight truncate max-w-[150px]">{shop?.name}</h3>
|
||||
<div className="text-base sm:text-lg font-black text-indigo-600 tracking-tighter">{currency(o.total)}</div>
|
||||
<h3 className="font-black text-base sm:text-lg text-slate-900 uppercase italic tracking-tight truncate max-w-[150px]">{shop?.name}</h3>
|
||||
<div className="text-xl font-black text-indigo-600 tracking-tighter">{currency(o.total)}</div>
|
||||
</div>
|
||||
<p className="text-[9px] text-slate-400 font-medium">{new Date(o.createdAt).toLocaleString('pt-PT')}</p>
|
||||
<div className="flex items-center justify-between pt-2 border-t border-slate-50">
|
||||
<div className="text-[9px] font-black text-slate-400 uppercase tracking-widest">
|
||||
{o.items.length} {o.items.length === 1 ? 'Item' : 'Itens'}
|
||||
<div className="flex items-center gap-2 text-[9px] text-slate-400 font-bold uppercase tracking-widest">
|
||||
<Clock size={10} />
|
||||
{new Date(o.createdAt).toLocaleString('pt-PT')}
|
||||
</div>
|
||||
<div className="flex items-center justify-between pt-4 border-t border-slate-50">
|
||||
<div className="flex -space-x-2">
|
||||
{o.items.slice(0, 3).map((_, i) => (
|
||||
<div key={i} className="w-6 h-6 rounded-full bg-slate-100 border-2 border-white flex items-center justify-center">
|
||||
<ShoppingBag size={10} className="text-slate-400" />
|
||||
</div>
|
||||
))}
|
||||
{o.items.length > 3 && (
|
||||
<div className="w-6 h-6 rounded-full bg-indigo-50 border-2 border-white flex items-center justify-center text-[8px] font-bold text-indigo-600">
|
||||
+{o.items.length - 3}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={`px-2 py-0.5 rounded-full text-[7px] font-black uppercase tracking-widest bg-${statusColor[o.status]}-100 text-${statusColor[o.status]}-700`}>
|
||||
<Badge className={`bg-${statusColor[o.status]}-50 text-${statusColor[o.status]}-600 border-none font-black uppercase text-[7px] tracking-widest`}>
|
||||
{statusLabel[o.status]}
|
||||
</div>
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -371,7 +370,7 @@ export default function Profile() {
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user