From d63c27ec12a279565cfa8711bd16e4bf6c841c02 Mon Sep 17 00:00:00 2001 From: 230417 <230417@epvc.pt> Date: Thu, 12 Mar 2026 17:54:19 +0000 Subject: [PATCH] =?UTF-8?q?altera=C3=A7=C3=B5es=20design?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/CartPanel.tsx | 114 +++++--- web/src/components/ProductList.tsx | 57 ++-- web/src/components/ServiceList.tsx | 37 ++- web/src/components/ShopCard.tsx | 96 +++---- web/src/components/layout/Header.tsx | 114 ++++---- web/src/components/ui/chip.tsx | 7 +- web/src/components/ui/tabs.tsx | 18 +- web/src/index.css | 29 +- web/src/pages/AuthLogin.tsx | 75 +++--- web/src/pages/AuthRegister.tsx | 134 +++++----- web/src/pages/Booking.tsx | 331 ++++++++++++----------- web/src/pages/Explore.tsx | 139 ++++++---- web/src/pages/Landing.tsx | 378 ++++++++++----------------- web/src/pages/Profile.tsx | 315 +++++++++++----------- web/src/pages/ShopDetails.tsx | 108 ++++---- 15 files changed, 1028 insertions(+), 924 deletions(-) diff --git a/web/src/components/CartPanel.tsx b/web/src/components/CartPanel.tsx index 73809dc..b6577c1 100644 --- a/web/src/components/CartPanel.tsx +++ b/web/src/components/CartPanel.tsx @@ -3,10 +3,27 @@ import { currency } from '../lib/format'; import { Card } from './ui/card'; import { Button } from './ui/button'; import { useApp } from '../context/AppContext'; +import { ShoppingBag, Trash2, ShoppingCart, ArrowRight, Package, Scissors } from 'lucide-react'; export const CartPanel = () => { const { cart, shops, removeFromCart, placeOrder, user } = useApp(); - if (!cart.length) return Carrinho vazio; + + if (!cart.length) { + return ( +
+
+ +
+
+

O seu carrinho está vazio

+

Explore os melhores produtos e serviços de luxo.

+
+ +
+ ); + } const grouped = cart.reduce>((acc, item) => { acc[item.shopId] = acc[item.shopId] || []; @@ -29,7 +46,7 @@ export const CartPanel = () => { }; return ( -
+
{Object.entries(grouped).map(([shopId, items]) => { const shop = shops.find((s) => s.id === shopId); const total = items.reduce((sum, i) => { @@ -39,42 +56,69 @@ export const CartPanel = () => { : shop?.products.find((p) => p.id === i.refId)?.price ?? 0; return sum + price * i.qty; }, 0); + return ( - -
-
-

{shop?.name ?? 'Barbearia'}

-

{shop?.address}

-
-
{currency(total)}
+
+
+ +

Origem: {shop?.name ?? 'Barbearia'}

-
- {items.map((i) => { - const ref = - i.type === 'service' - ? shop?.services.find((s) => s.id === i.refId) - : shop?.products.find((p) => p.id === i.refId); - return ( -
- - {i.type === 'service' ? 'Serviço: ' : 'Produto: '} - {ref?.name ?? 'Item'} x{i.qty} - - + + +
+
+ {items.map((i) => { + const ref = + i.type === 'service' + ? shop?.services.find((s) => s.id === i.refId) + : shop?.products.find((p) => p.id === i.refId); + + return ( +
+
+
+ {i.type === 'service' ? : } +
+
+

{ref?.name ?? 'Item'}

+

+ {i.qty} unidade{i.qty > 1 ? 's' : ''} • {currency(ref?.price || 0)} +

+
+
+ +
+ ); + })}
- ); - })} -
- {user ? ( - - ) : ( - - )} -
+ +
+
+

Total do Pedido

+

{currency(total)}

+
+ {user ? ( + + ) : ( + + )} +
+
+ +
); })}
diff --git a/web/src/components/ProductList.tsx b/web/src/components/ProductList.tsx index 54ce5bd..420c518 100644 --- a/web/src/components/ProductList.tsx +++ b/web/src/components/ProductList.tsx @@ -12,36 +12,47 @@ export const ProductList = ({ products: Product[]; onAdd?: (id: string) => void; }) => ( -
+
{products.map((p) => { const lowStock = p.stock <= 3; return ( - -
-
-
-

{p.name}

- {lowStock && ( - - - Stock baixo - - )} + +
+ + + {lowStock && ( +
+ + Últimas Unidades +
-
- - - {p.stock} {p.stock === 1 ? 'unidade' : 'unidades'} - + )} +
+ +
+
+

{p.name}

+
+ {p.stock} em stock
-
{currency(p.price)}
+ +
+
+ {currency(p.price)} +
+ + {onAdd && ( + + )} +
- {onAdd && ( - - )} ); })} diff --git a/web/src/components/ServiceList.tsx b/web/src/components/ServiceList.tsx index 9395bf1..c265740 100644 --- a/web/src/components/ServiceList.tsx +++ b/web/src/components/ServiceList.tsx @@ -11,23 +11,36 @@ export const ServiceList = ({ services: Service[]; onSelect?: (id: string) => void; }) => ( -
+
{services.map((s) => ( - -
-
-

{s.name}

-
- - {s.duration} minutos + +
+
+

{s.name}

+
+
+ + {s.duration} min +
+
+ Corte Profissional
-
{currency(s.price)}
+
+ {currency(s.price)} +
+ {onSelect && ( - +
+

Lugar disponível hoje

+ +
)} ))} diff --git a/web/src/components/ShopCard.tsx b/web/src/components/ShopCard.tsx index f4dc291..9e9e530 100644 --- a/web/src/components/ShopCard.tsx +++ b/web/src/components/ShopCard.tsx @@ -1,58 +1,66 @@ import { Link } from 'react-router-dom'; -import { Star, MapPin, Scissors } from 'lucide-react'; +import { Star, MapPin, Scissors, User } from 'lucide-react'; import { BarberShop } from '../types'; import { Card } from './ui/card'; import { Button } from './ui/button'; export const ShopCard = ({ shop }: { shop: BarberShop }) => { return ( - -
- {/* Avatar Circular com Badge de Rating */} -
-
- {shop.imageUrl ? ( - {shop.name} - ) : ( -
- -
- )} -
- {/* Rating Badge - Posicionado em cima à direita como na imagem base */} -
- - - {shop.rating ? shop.rating.toFixed(1) : '0.0'} - -
-
- - {/* Informações da Barbearia */} -
-

- {shop.name} -

-
- -

- {shop.address || 'Endereço Indisponível'} -

-
- -
- {(shop.services || []).length} serviços - - {(shop.barbers || []).length} barbeiros + +
+ {shop.imageUrl ? ( + {shop.name} + ) : ( +
+
+ )} +
+ + {/* Rating Badge */} +
+ + + {shop.rating ? shop.rating.toFixed(1) : '0.0'} +
- {/* Botões de Ação na base */} -
- +
+
+

+ {shop.name} +

+
+ +

+ {shop.address || 'Endereço Indisponível'} +

+
+
+ +
+
+
+ {[1, 2, 3].map(i => ( +
+ +
+ ))} +
+ + +{(shop.barbers || []).length} Barbeiros + +
+ + +
); diff --git a/web/src/components/layout/Header.tsx b/web/src/components/layout/Header.tsx index 1af1baa..f3bf0b5 100644 --- a/web/src/components/layout/Header.tsx +++ b/web/src/components/layout/Header.tsx @@ -15,35 +15,38 @@ export const Header = () => { } return ( -
-
+
+
setMobileMenuOpen(false)} > - Smart Agenda +
+ +
+ Smart Agenda {/* Desktop Navigation */} -
diff --git a/web/src/components/ui/chip.tsx b/web/src/components/ui/chip.tsx index 6236ce7..445ca40 100644 --- a/web/src/components/ui/chip.tsx +++ b/web/src/components/ui/chip.tsx @@ -1,11 +1,12 @@ import { cn } from '../../lib/cn'; -export const Chip = ({ children, active, onClick }: { children: React.ReactNode; active?: boolean; onClick?: () => void }) => ( +export const Chip = ({ children, active, onClick, className }: { children: React.ReactNode; active?: boolean; onClick?: () => void; className?: string }) => ( -
-

- Não tem conta?{' '} - - Criar conta +

+

+ Ainda não tem conta?{' '} + + Criar conta grátis

diff --git a/web/src/pages/AuthRegister.tsx b/web/src/pages/AuthRegister.tsx index 9d2a5a8..36d8ba0 100644 --- a/web/src/pages/AuthRegister.tsx +++ b/web/src/pages/AuthRegister.tsx @@ -108,31 +108,29 @@ export default function AuthRegister() { } return ( -
- -
-
- +
+ +
+
+ +
+
+

Criar Conta

+

Junte-se à Smart Agenda

-

- Criar conta -

-

- Escolha o tipo de acesso -

{error && ( -
+
{error}
)} -
+ {/* Tipo de conta */} -
-
- {/* Progress Steps */} -
- {steps.map((s, idx) => ( -
-
+ {/* Progress Steps - Premium Stepper */} +
+
+
+ {steps.map((s) => ( +
- +
{s.label} - +
- {idx < steps.length - 1 && ( -
- )} -
- ))} + ))} +
- - {/* Step Info Summary (Show what was already selected) */} - {step > 1 && selectedService && ( -
-
-
- -
-
-

Serviço Selecionado

-

{selectedService.name}

-
-
-
-

{currency(selectedService.price)}

-
-
- )} - - {step > 2 && selectedBarber && ( -
-
- -
-
-

Barbeiro

-

{selectedBarber.name}

-
-
- )} - + {/* Dynamic Step Content */} -
+
+ + {/* Step Back Button */} + {step > 1 && ( + + )} + {step === 1 && ( -
-
-
1
-

Escolha o serviço

+
+
+

1. Selecione o Serviço

+

O primeiro passo para a sua transformação de elite.

-
+
{shop.services.map((s) => ( ))}
@@ -233,12 +200,12 @@ export default function Booking() { )} {step === 2 && ( -
-
-
2
-

Escolha o barbeiro

+
+
+

2. Escolha o Mestre

+

Selecione o artista que cuidará do seu visual.

-
+
{shop.barbers.map((b) => ( ))} @@ -273,12 +241,15 @@ export default function Booking() { )} {step === 3 && ( -
-
-
3
-

Escolha a data

+
+
+

3. Defina o Momento

+

Seu tempo é valioso. Escolha a data perfeita.

-
+
+
+ +
)} {step === 4 && ( -
-
-
4
-

Escolha o horário

+
+
+

4. Escolha o Horário

+

A pontualidade é a cortesia dos reis.

-
-
- - {new Date(date).toLocaleDateString('pt-PT', { day: 'numeric', month: 'long', year: 'numeric' })} +
+ {/* Left Side: Summary Sidebar */} +
+
+
+
+
+

Serviço

+

{selectedService?.name}

+

{currency(selectedService?.price || 0)}

+
+
+

Mestre

+

{selectedBarber?.name}

+
+
+

Data

+

+ {new Date(date).toLocaleDateString('pt-PT', { day: 'numeric', month: 'long' })} +

+
+
+
- -
-
- {availableSlots.length > 0 ? ( - availableSlots.map((h) => ( - - )) - ) : ( -
-

Infelizmente não há horários livres para este dia.

+ {/* Right Side: Slots Grid */} +
+
+ {availableSlots.length > 0 ? ( + availableSlots.map((h) => ( + + )) + ) : ( +
+

Sem disponibilidade para este dia

+
+ )}
- )} -
- {/* Final Summary & Confirmation */} - {canSubmit && ( -
-
-
-

Total a pagar

-

{currency(selectedService?.price || 0)}

+ {canSubmit && ( +
+ +

+ Pagamento realizado após o serviço +

- -
+ )}
- )} +
)}
diff --git a/web/src/pages/Explore.tsx b/web/src/pages/Explore.tsx index fe72cb4..f63a165 100644 --- a/web/src/pages/Explore.tsx +++ b/web/src/pages/Explore.tsx @@ -10,7 +10,8 @@ import { Card } from '../components/ui/card'; import { Chip } from '../components/ui/chip'; import { Input } from '../components/ui/input'; import { useApp } from '../context/AppContext'; -import { Search } from 'lucide-react'; +import { Search, Star } from 'lucide-react'; +import { Button } from '../components/ui/button'; export default function Explore() { const { shops } = useApp(); @@ -52,66 +53,94 @@ export default function Explore() { }, [shops, query, filter, sortBy]); return ( -
-
-

Explorar

-
-
-

Barbearias

-

Escolha a sua favorita e agende em minutos.

+
+
+
+
+
+ + As melhores Barbearias +
+

+ Explorar Espaços +

+

Descubra barbearias exclusivas e reserve o seu próximo corte em segundos.

+
+
+ {filtered.length} Espaços Disponíveis
-
{filtered.length} resultados
- -
-
- setQuery(e.target.value)} - placeholder="Pesquisar por nome ou endereço..." - className="pl-11" - /> - +
+ +
+
+ + setQuery(e.target.value)} + placeholder="Pesquisar por nome ou endereço..." + className="h-14 pl-14 pr-6 bg-transparent border-none text-lg font-medium focus:ring-0 placeholder:text-slate-400" + /> +
+ +
+ +
+ setFilter('todas')} + className={`h-11 px-6 rounded-2xl font-bold uppercase tracking-tight transition-all ${filter === 'todas' ? '!bg-slate-900 !text-amber-500 border-none shadow-lg' : 'bg-slate-100 text-slate-500 hover:bg-slate-200'}`} + > + Todas + + setFilter('top')} + className={`h-11 px-6 rounded-2xl font-bold uppercase tracking-tight transition-all ${filter === 'top' ? '!bg-slate-900 !text-amber-500 border-none shadow-lg' : 'bg-slate-100 text-slate-500 hover:bg-slate-200'}`} + > + Top Avaliadas + + + +
- -
- -
- setFilter('todas')}> - Todas - - setFilter('top')}> - Top avaliadas - -
-
- - {!useApp().shopsReady ? ( -
-
-

A carregar barbearias...

-
- ) : filtered.length === 0 ? ( - -

Nenhuma barbearia encontrada

-

Tente ajustar a pesquisa ou limpar os filtros.

- ) : ( -
- {filtered.map((shop) => ( - - ))} -
- )} + + {!useApp().shopsReady ? ( +
+
+

A carregar espaços...

+
+ ) : filtered.length === 0 ? ( + +
+ +
+
+

Nenhuma barbearia encontrada

+

Tente ajustar o termo de pesquisa ou os filtros ativos.

+
+ +
+ ) : ( +
+ {filtered.map((shop) => ( + + ))} +
+ )} +
); } diff --git a/web/src/pages/Landing.tsx b/web/src/pages/Landing.tsx index ad5396a..a6ace22 100644 --- a/web/src/pages/Landing.tsx +++ b/web/src/pages/Landing.tsx @@ -31,299 +31,209 @@ export default function Landing() { const featuredShops = mockShops.slice(0, 3); return ( -
- {/* Hero Section */} -
-
-
-
+
+ {/* Hero Section - Midnight Luxury Style */} +
+
+
+
-
-
- - Revolucione sua barbearia +
+
+ + O Novo Standard do Cuidado Masculino
-

- Agendamentos, produtos e gestão em um{' '} - único lugar +

+ Elegância em cada
+ Agendamento

-

- Experiência mobile-first para clientes e painel completo para barbearias. - Simplifique a gestão do seu negócio e aumente sua receita. +

+ Transforme a rotina da sua barbearia com uma experiência digital digna de um cavalheiro. + Mobile-first, premium e inteligente.

-
- -
- {/* Stats */} -
-
-
500+
-
Barbearias
+ {/* Stats Bar */} +
+
+
500+
+
Espaços de Luxo
-
-
10k+
-
Agendamentos
+
+
10K+
+
Cortes Marcados
-
-
4.8
-
Avaliação média
+
+
4.9
+
Rating de Elite
- {/* Features Grid */} -
-
-

- Tudo que você precisa -

-

- Funcionalidades poderosas para clientes e barbearias -

+ {/* Hero Image Mockup (Place with a generated-like look) */} +
+
+
+
+
+ +

Smart Agenda Elite Edition

+
+
+
+
+
+
+
+
+
+ + {/* Features - Minimalist & Bold */} +
+
+
+

+ Ecossistema
Completo +

+

+ Tudo o que a sua barbearia precisa para escalar com sofisticação. +

+
-
+
{[ { - icon: Calendar, - title: 'Agendamentos Inteligentes', - desc: 'Escolha serviço, barbeiro, data e horário com validação de slots em tempo real. Notificações automáticas.', - color: 'from-blue-500 to-blue-600' + icon: Clock, + title: 'Gestão Cirúrgica', + desc: 'Controle de horários com precisão absoluta. Slot management inteligente e automação de reserva.', + color: 'bg-slate-950 shadow-[0_15px_35px_rgba(0,0,0,0.15)]' }, { icon: ShoppingBag, - title: 'Carrinho Inteligente', - desc: 'Produtos e serviços agrupados por barbearia, checkout rápido e seguro. Histórico completo de compras.', - color: 'from-emerald-500 to-emerald-600' + title: 'Curadoria de Produtos', + desc: 'Venda produtos de elite diretamente no ecossistema. Gestão de stock e carrinho omnicanal.', + color: 'bg-white border-2 border-slate-50' }, { icon: BarChart3, - title: 'Painel Completo', - desc: 'Faturamento, agendamentos, pedidos e análises detalhadas. Tudo no controle da sua barbearia.', - color: 'from-purple-500 to-purple-600' - }, - { - icon: Users, - title: 'Gestão de Barbeiros', - desc: 'Gerencie horários, especialidades e disponibilidade de cada barbeiro. Calendário integrado.', - color: 'from-indigo-500 to-indigo-600' - }, - { - icon: Clock, - title: 'Horários Flexíveis', - desc: 'Configure horários de funcionamento, intervalos e disponibilidade. Sistema automático de bloqueio.', - color: 'from-orange-500 to-orange-600' - }, - { - icon: Shield, - title: 'Seguro e Confiável', - desc: 'Dados protegidos, pagamentos seguros e backup automático. Conformidade com LGPD.', - color: 'from-rose-500 to-rose-600' + title: 'Analytics de Luxo', + desc: 'Relatórios detalhados de faturamento, performance de barbeiros e taxas de retenção.', + color: 'bg-white border-2 border-slate-50' }, ].map((feature) => ( - -
- + +
+
-
-

{feature.title}

-

{feature.desc}

+
+

{feature.title}

+

{feature.desc}

))}
- {/* How it Works */} -
-
-

- Como funciona -

-

- Simples, rápido e eficiente em 3 passos -

-
+ {/* How it Works - Immersive */} +
+
+
+
+

+ A Jornada do Cavalheiro +

+
+
-
- {[ - { step: '1', title: 'Explore', desc: 'Navegue pelas barbearias disponíveis, veja avaliações e serviços oferecidos.' }, - { step: '2', title: 'Agende', desc: 'Escolha o serviço, barbeiro e horário que melhor se adequa à sua agenda.' }, - { step: '3', title: 'Aproveite', desc: 'Compareça no horário agendado e aproveite um serviço de qualidade.' }, - ].map((item) => ( -
-
- {item.step} +
+ {[ + { step: '01', title: 'Descobrir', desc: 'Encontre os espaços mais exclusivos da cidade com avaliações reais.' }, + { step: '02', title: 'Personalizar', desc: 'Escolha o seu barbeiro de confiança e o seu horário preferido.' }, + { step: '03', title: 'Vivenciar', desc: 'Receba o tratamento de elite que você merece, sem esperas.' }, + ].map((item, idx) => ( +
+
+
+ {item.step} +
+
+ {item.step} +
+
+
+

{item.title}

+

{item.desc}

+
-

{item.title}

-

{item.desc}

-
- ))} + ))} +
- {/* Featured Shops */} -
-
-
-

- Barbearias em destaque + {/* Featured Shops - Premium Row */} +
+
+
+

+ Clubes Membros

-

- Conheça algumas das melhores barbearias da plataforma -

+

As melhores barbearias do país

-
-
+
{featuredShops.map((shop) => ( ))}
- -
- -
- {/* Benefits */} -
- -
- -
-

- Mobile-First -

-

- Interface otimizada para dispositivos móveis. Agende de qualquer lugar, - a qualquer hora. Experiência fluida e responsiva. -

-
    - {['Design responsivo', 'Carregamento rápido', 'Interface intuitiva'].map((item) => ( -
  • - - {item} -
  • - ))} -
-
+ {/* Final CTA - Immersive Dark */} +
+
+
+
- -
- -
-

- Aumente sua Receita -

-

- Ferramentas poderosas para gerenciar seu negócio. Análises detalhadas, - gestão de estoque e muito mais. -

-
    - {['Análises em tempo real', 'Gestão de estoque', 'Relatórios detalhados'].map((item) => ( -
  • - - {item} -
  • - ))} -
-
-
- - {/* Testimonials */} -
-
-

- O que nossos clientes dizem -

-

- Depoimentos reais de quem usa a plataforma -

-
- -
- {[ - { - name: 'João Silva', - role: 'Cliente', - text: 'Facilita muito agendar meu corte. Interface simples e rápida. Recomendo!', - rating: 5 - }, - { - name: 'Carlos Mendes', - role: 'Proprietário', - text: 'O painel é completo e me ajuda muito na gestão. Aumentou minha organização.', - rating: 5 - }, - { - name: 'Miguel Santos', - role: 'Cliente', - text: 'Nunca mais perco horário. As notificações são muito úteis.', - rating: 5 - }, - ].map((testimonial) => ( - -
- {[...Array(testimonial.rating)].map((_, i) => ( - - ))} -
- -

{testimonial.text}

-
-
{testimonial.name}
-
{testimonial.role}
-
-
- ))} -
-
- - {/* CTA Final */} -
-
-
- -
-

- Pronto para começar? -

-

- Junte-se a centenas de barbearias que já estão usando a Smart Agenda - para revolucionar seus negócios. -

-
- - +
+

+ Faça Parte
do Legado +

+

+ Centenas de profissionais já elevaram o seu negócio ao próximo nível. + A sua barbearia merece o melhor. +

+
+ + +
diff --git a/web/src/pages/Profile.tsx b/web/src/pages/Profile.tsx index e12b0d7..7c61f03 100644 --- a/web/src/pages/Profile.tsx +++ b/web/src/pages/Profile.tsx @@ -10,7 +10,7 @@ import { Badge } from '../components/ui/badge' import { Button } from '../components/ui/button' import { currency } from '../lib/format' import { useApp } from '../context/AppContext' -import { Calendar, ShoppingBag, User, Clock, Heart, Star, MapPin } from 'lucide-react' +import { Calendar, ShoppingBag, User, Clock, Heart, Star, MapPin, CheckCircle2 } from 'lucide-react' import { supabase } from '../lib/supabase' import { ReviewModal } from '../components/ReviewModal' @@ -130,60 +130,67 @@ export default function Profile() { /> )} -
- {/* Profile Header */} - -
-
- +
+ {/* Profile Header - Luxury Style */} +
+
+
+
+
+
+ +
-
-

Olá, {displayName}!

-

{authEmail}

-
- Cliente - {favoriteShops.length > 0 && ( - - {favoriteShops.length} favorita{favoriteShops.length > 1 ? 's' : ''} - - )} +
+
+ + Membro de Elite
+

+ {displayName} +

+

{authEmail}

- +
- {/* ❤️ Barbearias Favoritas */} + {/* ❤️ Barbearias Favoritas - Horizontal Scroll or Grid */} {favoriteShops.length > 0 && ( -
-
- -

Barbearias Favoritas

- {favoriteShops.length} +
+
+
+ +

Cofre de Favoritos

+
+ {favoriteShops.length} Espaços
-
+
{favoriteShops.map((shop) => ( - - {shop.imageUrl ? ( - {shop.name} - ) : ( -
- + +
+
+ {shop.imageUrl ? ( + {shop.name} + ) : ( +
+ +
+ )} +
+
+

{shop.name}

+
+
+ + {shop.rating.toFixed(1)} +
+
+ + {shop.address.split(',')[0]} +
+
- )} -
-

{shop.name}

- {shop.address && ( -

- {shop.address} -

- )} - {shop.rating > 0 && ( -

- - {shop.rating.toFixed(1)} -

- )}
@@ -192,117 +199,123 @@ export default function Profile() {
)} - {/* Agendamentos */} -
-
- -

Agendamentos

- {myAppointments.length} -
- - {!myAppointments.length ? ( - - -

Nenhum agendamento ainda

-

Explore barbearias e agende o seu primeiro serviço!

-
- ) : ( -
- {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 ( - -
-
-
-

{shop?.name}

- - {statusLabel[a.status]} - -
- {service && ( -

- - {service.name} · {service.duration} min -

- )} -

{a.date}

- {/* Botão de avaliar */} - {canReview && ( - - )} - {a.status === 'concluido' && reviewedAppointments.has(a.id) && ( -

- ✓ Avaliado -

- )} -
-
-

{currency(a.total)}

-
-
-
- ) - })} +
+ {/* Main Column: Appointments */} +
+
+
+ +

Minha Agenda

+
- )} -
- {/* Pedidos */} -
-
- -

Pedidos

- {myOrders.length} -
+ {!myAppointments.length ? ( + + +

Sem Reservas

+

Sua jornada de estilo ainda não começou.

+ +
+ ) : ( +
+ {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 ( + +
+
+
+
+

{shop?.name}

+
+ {statusLabel[a.status]} +
+
+

{a.date}

+
+
+ {currency(a.total)} +
+
- {!myOrders.length ? ( - - -

Nenhum pedido ainda

-

Adicione produtos ao carrinho e finalize o primeiro pedido!

-
- ) : ( -
- {myOrders.map((o) => { - const shop = shops.find((s) => s.id === o.shopId) - return ( - -
-
-
-

{shop?.name}

- - {statusLabel[o.status]} - -
-

- {new Date(o.createdAt).toLocaleDateString('pt-PT', { - day: '2-digit', month: 'long', year: 'numeric' - })} -

-

- {o.items.length} {o.items.length === 1 ? 'item' : 'itens'} -

+
+ {service && ( +
+ + {service.name} · {service.duration} MIN +
+ )} + + {canReview && ( + + )} + + {a.status === 'concluido' && reviewedAppointments.has(a.id) && ( +
+ + Avaliado +
+ )} +
-
-

{currency(o.total)}

-
-
-
- ) - })} + + ) + })} +
+ )} +
+ + {/* Side Column: Orders */} +
+
+
+ +

Pedidos

+
- )} -
+ + {!myOrders.length ? ( + +

Sem encomendas efetuadas.

+
+ ) : ( +
+ {myOrders.map((o) => { + const shop = shops.find((s) => s.id === o.shopId) + return ( + +
+
+

{shop?.name}

+
{currency(o.total)}
+
+
+
+ {o.items.length} {o.items.length === 1 ? 'Item' : 'Itens'} +
+
+ {statusLabel[o.status]} +
+
+
+
+ ) + })} +
+ )} +
+
) diff --git a/web/src/pages/ShopDetails.tsx b/web/src/pages/ShopDetails.tsx index 8356440..41067f2 100644 --- a/web/src/pages/ShopDetails.tsx +++ b/web/src/pages/ShopDetails.tsx @@ -37,87 +37,97 @@ export default function ShopDetails() { )}`; return ( -
-
+
+
{shop.imageUrl ? ( - {`Foto + {`Foto ) : ( -
+
)} -
-
+
+ +
- +
-
-
- - {(shop.rating || 0).toFixed(1)} + +
+
+ + {(shop.rating || 0).toFixed(1)} EXCELENTE +
+

{shop.name}

+
+ +

{shop.address}

-

{shop.name}

-

{shop.address}

-
-
- {(shop.services || []).length} serviços · {(shop.barbers || []).length} barbeiros +
+
+ setTab(v as typeof tab)} + className="border-none bg-transparent" + /> +
+ {(shop.services || []).length} SERVIÇOS · {(shop.barbers || []).length} BARBEIROS +
+
+ +
+ {tab === 'servicos' ? ( + { + window.location.href = `/agendar/${shop.id}?service=${sid}`; + }} + /> + ) : tab === 'barbeiros' ? ( +
+ +
+ ) : ( + addToCart({ shopId: shop.id, type: 'product', refId: pid, qty: 1 })} /> + )}
- setTab(v as typeof tab)} - /> - {tab === 'servicos' ? ( - { - // Navega para a página de agendamento com o serviço pré-selecionado - window.location.href = `/agendar/${shop.id}?service=${sid}`; - }} - /> - ) : tab === 'barbeiros' ? ( - - ) : ( - addToCart({ shopId: shop.id, type: 'product', refId: pid, qty: 1 })} /> - )} setImageOpen(false)}> {shop.imageUrl ? ( - {`Foto + {`Foto ) : ( -
+
)}