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 && (
+
+
+
+
+ )}
+
+
+
+ );
+};
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 };