From 005c2da2753d53d410b8787d3ce08970eca41704 Mon Sep 17 00:00:00 2001 From: 230417 <230417@epvc.pt> Date: Tue, 17 Mar 2026 16:09:07 +0000 Subject: [PATCH] feat: Add shop details tab displaying schedule, payment methods, social links, and contacts. --- web/src/components/ShopDetailsTab.tsx | 131 ++++++++++++++++++++++++++ web/src/pages/ShopDetails.tsx | 8 +- web/src/types.ts | 16 +++- 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 web/src/components/ShopDetailsTab.tsx diff --git a/web/src/components/ShopDetailsTab.tsx b/web/src/components/ShopDetailsTab.tsx new file mode 100644 index 0000000..7081644 --- /dev/null +++ b/web/src/components/ShopDetailsTab.tsx @@ -0,0 +1,131 @@ +import { BarberShop } from '../types'; +import { Copy, Facebook, Instagram, Phone, Smartphone } from 'lucide-react'; + +export const ShopDetailsTab = ({ shop }: { shop: BarberShop }) => { + // Mock data if not provided (matches screenshot vibe) + const schedule = shop.schedule || [ + { day: 'Segunda-feira', open: '09:00', close: '19:30' }, + { day: 'Terça-feira', open: '09:00', close: '19:30' }, + { day: 'Quarta-feira', open: '09:00', close: '19:30' }, + { day: 'Quinta-feira', open: '09:00', close: '19:30' }, + { day: 'Sexta-feira', open: '09:00', close: '19:30' }, + { day: 'Sábado', open: '09:00', close: '19:00' }, + { day: 'Domingo', open: '', close: '', closed: true }, + ]; + + const paymentMethods = shop.paymentMethods || ['Dinheiro', 'Cartão de Crédito', 'Cartão de Débito']; + + const socials = shop.socialNetworks || { + whatsapp: 'https://wa.me/351900000000', + instagram: 'https://instagram.com', + facebook: 'https://facebook.com' + }; + + const contacts = shop.contacts || { + phone1: '252 048 754', + phone2: '252 048 754' + }; + + const currentDayIndex = new Date().getDay() === 0 ? 6 : new Date().getDay() - 1; // 0 for Monday, 6 for Sunday + + const copyToClipboard = (text: string) => { + navigator.clipboard.writeText(text); + }; + + return ( +
+ {/* Horário de atendimento */} +
+

Horário de atendimento

+
+ {schedule.map((slot, i) => ( +
+
+ {slot.day} + {i === currentDayIndex && ( + Hoje + )} +
+ + {slot.closed ? 'Fechado' : `${slot.open} - ${slot.close}`} + +
+ ))} +
+
+ +
+ + {/* Formas de pagamento */} +
+

Formas de pagamento

+
+ {paymentMethods.map((method, i) => ( + + {method} + + ))} +
+
+ +
+ + {/* Redes Sociais */} +
+

Redes Sociais

+
+ {socials.whatsapp && ( + + + + )} + {socials.instagram && ( + + + + )} + {socials.facebook && ( + + + + )} +
+
+ +
+ + {/* Contacto */} +
+

Contacto

+
+ {contacts.phone1 && ( +
+
+
+ +
+ {contacts.phone1} +
+ +
+ )} + {contacts.phone2 && ( +
+
+
+ +
+ {contacts.phone2} +
+ +
+ )} +
+
+
+ ); +}; diff --git a/web/src/pages/ShopDetails.tsx b/web/src/pages/ShopDetails.tsx index 0e1b3e0..5aeb88a 100644 --- a/web/src/pages/ShopDetails.tsx +++ b/web/src/pages/ShopDetails.tsx @@ -10,6 +10,7 @@ import { Tabs } from '../components/ui/tabs'; import { ServiceList } from '../components/ServiceList'; import { ProductList } from '../components/ProductList'; import { BarberList } from '../components/BarberList'; +import { ShopDetailsTab } from '../components/ShopDetailsTab'; import { Button } from '../components/ui/button'; import { useApp } from '../context/AppContext'; import { Dialog } from '../components/ui/dialog'; @@ -19,7 +20,7 @@ export default function ShopDetails() { const { id } = useParams<{ id: string }>(); const { shops, shopsReady, addToCart, toggleFavorite, isFavorite } = useApp(); const shop = useMemo(() => shops.find((s) => s.id === id), [shops, id]); - const [tab, setTab] = useState<'servicos' | 'produtos' | 'barbeiros'>('servicos'); + const [tab, setTab] = useState<'servicos' | 'produtos' | 'barbeiros' | 'detalhes'>('servicos'); const [imageOpen, setImageOpen] = useState(false); if (!shopsReady) { @@ -95,6 +96,7 @@ export default function ShopDetails() { { id: 'servicos', label: 'Serviços' }, { id: 'barbeiros', label: 'Barbeiros' }, { id: 'produtos', label: 'Produtos' }, + { id: 'detalhes', label: 'Detalhes' }, ]} active={tab} onChange={(v) => setTab(v as typeof tab)} @@ -117,6 +119,10 @@ export default function ShopDetails() {
+ ) : tab === 'detalhes' ? ( +
+ +
) : ( addToCart({ shopId: shop.id, type: 'product', refId: pid, qty: 1 })} /> )} diff --git a/web/src/types.ts b/web/src/types.ts index b4da3c7..e6ff74a 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -1,7 +1,21 @@ export type Barber = { id: string; name: string; imageUrl?: string; specialties: string[]; schedule: { day: string; slots: string[] }[] }; export type Service = { id: string; name: string; price: number; duration: number; barberIds: string[] }; export type Product = { id: string; name: string; price: number; stock: number }; -export type BarberShop = { id: string; name: string; address: string; rating: number; services: Service[]; products: Product[]; barbers: Barber[]; imageUrl?: string }; +export type ShopSchedule = { day: string; open: string; close: string; closed?: boolean }; +export type BarberShop = { + id: string; + name: string; + address: string; + rating: number; + services: Service[]; + products: Product[]; + barbers: Barber[]; + imageUrl?: string; + schedule?: ShopSchedule[]; + paymentMethods?: string[]; + socialNetworks?: { whatsapp?: string; instagram?: string; facebook?: string }; + contacts?: { phone1?: string; phone2?: string }; +}; export type AppointmentStatus = 'pendente' | 'confirmado' | 'concluido' | 'cancelado'; export type OrderStatus = 'pendente' | 'confirmado' | 'concluido' | 'cancelado'; export type Appointment = { id: string; shopId: string; serviceId: string; barberId: string; customerId: string; date: string; status: AppointmentStatus; total: number };