alteração dashboard

This commit is contained in:
2026-03-11 10:28:25 +00:00
parent 35c0eb4844
commit 198263b455

View File

@@ -118,11 +118,7 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
const [activeTab, setActiveTab] = useState<TabId>('overview');
const [period, setPeriod] = useState<keyof typeof periods>('semana');
const [appointmentView, setAppointmentView] = useState<'list' | 'calendar'>('list');
const [currentWeek, setCurrentWeek] = useState(new Date());
const [searchQuery, setSearchQuery] = useState('');
const [includeCancelled, setIncludeCancelled] = useState(false);
const [selectedDate, setSelectedDate] = useState(new Date());
// Form states
const [svcName, setSvcName] = useState('');
@@ -148,67 +144,7 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
const allShopAppointments = appointments.filter((a) => a.shopId === shop.id && periodMatch(parseDate(a.date)));
// Agendamentos ativos (não concluídos e não cancelados)
const shopAppointments = allShopAppointments.filter((a) => a.status !== 'concluido');
// Agendamentos concluídos (histórico passado)
const completedAppointments = allShopAppointments.filter((a) => a.status === 'concluido');
// Estatísticas para lista de marcações (do dia selecionado)
const selectedDateAppointments = appointments.filter((a) => {
if (a.shopId !== shop.id) return false;
const aptDate = new Date(a.date.replace(' ', 'T'));
return (
aptDate.getDate() === selectedDate.getDate() &&
aptDate.getMonth() === selectedDate.getMonth() &&
aptDate.getFullYear() === selectedDate.getFullYear()
);
});
const totalBookingsToday = selectedDateAppointments.filter((a) => includeCancelled || a.status !== 'cancelado').length;
const newClientsToday = useMemo(() => {
const clientIds = new Set(selectedDateAppointments.map((a) => a.customerId));
return clientIds.size;
}, [selectedDateAppointments]);
const onlineBookingsToday = selectedDateAppointments.filter((a) => a.status !== 'cancelado').length;
const occupancyRate = useMemo(() => {
// Calcular ocupação baseada em slots disponíveis (8h-18h = 20 slots de 30min)
const totalSlots = 20;
const bookedSlots = selectedDateAppointments.filter((a) => a.status !== 'cancelado').length;
return Math.round((bookedSlots / totalSlots) * 100);
}, [selectedDateAppointments]);
// Comparação com semana passada (simplificado - sempre 0% por enquanto)
const comparisonPercent = 0;
// Filtrar agendamentos para lista
const filteredAppointments = useMemo(() => {
let filtered = selectedDateAppointments;
if (!includeCancelled) {
filtered = filtered.filter((a) => a.status !== 'cancelado');
}
if (searchQuery) {
filtered = filtered.filter((a) => {
const service = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
const customer = users.find((u) => u.id === a.customerId);
const searchLower = searchQuery.toLowerCase();
return (
service?.name.toLowerCase().includes(searchLower) ||
barber?.name.toLowerCase().includes(searchLower) ||
customer?.name.toLowerCase().includes(searchLower) ||
customer?.email.toLowerCase().includes(searchLower) ||
a.date.toLowerCase().includes(searchLower)
);
});
}
return filtered;
}, [selectedDateAppointments, includeCancelled, searchQuery, shop.services, shop.barbers, users]);
const shopAppointments = allShopAppointments.filter((a) => a.status !== 'concluido' && a.status !== 'cancelado');
// Pedidos apenas com produtos (não serviços)
const shopOrders = orders.filter(
@@ -454,66 +390,32 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
<div className="grid md:grid-cols-3 gap-6">
{/* Coluna Principal - Esquerda */}
<div className="md:col-span-2 space-y-6">
{/* Reservas de Hoje */}
{/* Calendário de Visão Geral */}
<Card className="p-6">
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-indigo-100 rounded-lg">
<Search size={20} className="text-indigo-600" />
</div>
<div>
<h3 className="text-lg font-bold text-slate-900">Reservas de hoje</h3>
<p className="text-sm text-slate-600">Verá aqui as reservas de hoje assim que chegarem</p>
</div>
</div>
{(() => {
const today = new Date();
const todayAppts = allShopAppointments.filter(a => {
const aptDate = new Date(a.date.replace(' ', 'T'));
return aptDate.toDateString() === today.toDateString();
});
if (todayAppts.length === 0) {
return (
<div className="text-center py-8">
<Calendar size={48} className="mx-auto text-slate-300 mb-3" />
<p className="text-slate-600 font-medium mb-2">Sem reservas hoje</p>
<Button variant="outline" size="sm" onClick={() => setActiveTab('appointments')}>
Ir para o calendário
<ArrowRight size={16} className="ml-2" />
</Button>
</div>
);
}
return (
<div className="space-y-2">
{todayAppts.slice(0, 3).map(a => {
const svc = shop.services.find(s => s.id === a.serviceId);
const barber = shop.barbers.find(b => b.id === a.barberId);
const customer = users.find(u => u.id === a.customerId);
const aptDate = new Date(a.date.replace(' ', 'T'));
const timeStr = aptDate.toLocaleTimeString('pt-PT', { hour: '2-digit', minute: '2-digit' });
return (
<div key={a.id} className="flex items-center justify-between p-3 border border-slate-200 rounded-lg hover:bg-slate-50">
<div className="flex-1">
<p className="font-semibold text-slate-900">{customer?.name || 'Cliente'}</p>
<p className="text-sm text-slate-600">{timeStr} · {svc?.name || 'Serviço'}</p>
</div>
<Badge color={a.status === 'pendente' ? 'amber' : a.status === 'confirmado' ? 'green' : 'red'}>
{a.status}
</Badge>
</div>
);
})}
{todayAppts.length > 3 && (
<Button variant="outline" size="sm" className="w-full" onClick={() => setActiveTab('appointments')}>
Ver todas ({todayAppts.length})
</Button>
)}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3">
<div className="p-2 bg-indigo-100 rounded-lg">
<Calendar size={20} className="text-indigo-600" />
</div>
);
})()}
<div>
<h3 className="text-lg font-bold text-slate-900">Calendário de Reservas</h3>
<p className="text-sm text-slate-600">Visão panorâmica da semana atual</p>
</div>
</div>
<Button variant="outline" size="sm" onClick={() => setActiveTab('appointments')}>
Gerir Pedidos
<ArrowRight size={16} className="ml-2" />
</Button>
</div>
{/* Reutiliza o Componente de Calendário Inteiro na aba Overview */}
<CalendarWeekView
week={currentWeek}
appointments={shopAppointments}
shop={shop}
onWeekChange={setCurrentWeek}
onStatusChange={updateAppointmentStatus}
/>
</Card>
</div>
@@ -635,311 +537,190 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
)}
{activeTab === 'appointments' && (
<div className="space-y-4">
{/* View Toggle Buttons */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<button
onClick={() => setAppointmentView('list')}
className={`flex items-center gap-2 px-4 py-2 rounded-lg border-2 transition-all ${appointmentView === 'list'
? 'border-indigo-500 bg-indigo-50 text-indigo-700 font-semibold'
: 'border-slate-200 text-slate-700 hover:border-indigo-300 hover:bg-indigo-50/50'
}`}
>
<List size={18} />
<span>Lista de marcações</span>
</button>
<button
onClick={() => setAppointmentView('calendar')}
className={`flex items-center gap-2 px-4 py-2 rounded-lg border-2 transition-all ${appointmentView === 'calendar'
? 'border-indigo-500 bg-indigo-50 text-indigo-700 font-semibold'
: 'border-slate-200 text-slate-700 hover:border-indigo-300 hover:bg-indigo-50/50'
}`}
>
<Calendar size={18} />
<span>Calendário</span>
</button>
<div className="space-y-6">
<div className="flex items-center justify-between mb-2">
<div>
<h2 className="text-xl font-bold text-slate-900">Caixa de Pedidos</h2>
<p className="text-sm text-slate-600">Aprove ou recuse os pedidos pendentes e conclua os serviços de hoje.</p>
</div>
<Badge color="slate" variant="soft">{shopAppointments.length} no período</Badge>
<Badge color="amber" variant="soft">{pendingAppts} Novos Pedidos</Badge>
</div>
{/* List View */}
{appointmentView === 'list' && (
<div className="space-y-6">
{/* Cards de Estatísticas */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<Card className="p-5">
<div className="flex items-center justify-between mb-2">
<div className="p-2 bg-indigo-500 rounded-lg text-white">
<Calendar size={20} />
</div>
<span className={`text-xs ${comparisonPercent >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{comparisonPercent >= 0 ? '+' : ''}{comparisonPercent}%
</span>
</div>
<p className="text-sm text-slate-600 mb-1">Total de marcações</p>
<p className="text-2xl font-bold text-slate-900">{totalBookingsToday}</p>
<p className="text-xs text-slate-500 mt-1">
Comparado com {totalBookingsToday} no mesmo dia da semana passada
</p>
</Card>
<Card className="p-5">
<div className="flex items-center justify-between mb-2">
<div className="p-2 bg-green-500 rounded-lg text-white">
<UserPlus size={20} />
</div>
<span className={`text-xs ${comparisonPercent >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{comparisonPercent >= 0 ? '+' : ''}{comparisonPercent}%
</span>
</div>
<p className="text-sm text-slate-600 mb-1">Novos clientes</p>
<p className="text-2xl font-bold text-slate-900">{newClientsToday}</p>
<p className="text-xs text-slate-500 mt-1">
Comparado com {newClientsToday} no mesmo dia da semana passada
</p>
</Card>
<Card className="p-5">
<div className="flex items-center justify-between mb-2">
<div className="p-2 bg-blue-500 rounded-lg text-white">
<Globe size={20} />
</div>
<span className={`text-xs ${comparisonPercent >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{comparisonPercent >= 0 ? '+' : ''}{comparisonPercent}%
</span>
</div>
<p className="text-sm text-slate-600 mb-1">Marcações online</p>
<p className="text-2xl font-bold text-slate-900">{onlineBookingsToday}</p>
<p className="text-xs text-slate-500 mt-1">
Comparado com {onlineBookingsToday} no mesmo dia da semana passada
</p>
</Card>
<Card className="p-5">
<div className="flex items-center justify-between mb-2">
<div className="p-2 bg-purple-500 rounded-lg text-white">
<TrendingUp size={20} />
</div>
<span className={`text-xs ${comparisonPercent >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{comparisonPercent >= 0 ? '+' : ''}{comparisonPercent}%
</span>
</div>
<p className="text-sm text-slate-600 mb-1">Ocupação</p>
<p className="text-2xl font-bold text-slate-900">{occupancyRate}%</p>
<p className="text-xs text-slate-500 mt-1">
Comparado com {occupancyRate}% no mesmo dia da semana passada
</p>
</Card>
</div>
{/* Barra de Pesquisa e Filtros */}
<div className="flex flex-col md:flex-row gap-4 items-start md:items-center justify-between">
<div className="flex-1 max-w-md">
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" size={18} />
<input
type="text"
placeholder="Pesquisar por cliente"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full rounded-lg border border-slate-300 bg-white px-10 py-2.5 text-sm text-slate-900 placeholder:text-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/30 transition-all"
/>
</div>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setIncludeCancelled(!includeCancelled)}
className={`flex items-center gap-2 px-4 py-2 rounded-lg border-2 transition-all ${includeCancelled
? 'border-indigo-500 bg-indigo-50 text-indigo-700'
: 'border-slate-200 text-slate-700 hover:border-indigo-300'
}`}
>
<span>Incluir cancelamentos</span>
<ChevronDown size={16} />
</button>
<Button variant="outline" size="sm">
<Printer size={18} className="mr-2" />
Imprimir
</Button>
</div>
</div>
{/* Navegação de Data */}
<div className="flex items-center gap-4">
<Button variant="outline" size="sm" onClick={() => setSelectedDate(new Date())}>
Hoje
</Button>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={() => {
const newDate = new Date(selectedDate);
newDate.setDate(newDate.getDate() - 1);
setSelectedDate(newDate);
}}>
<ChevronLeft size={18} />
</Button>
<div className="text-sm font-medium text-slate-700 px-3">
{selectedDate.toLocaleDateString('pt-PT', {
weekday: 'long',
day: 'numeric',
month: 'numeric',
year: 'numeric'
})}
</div>
<Button variant="outline" size="sm" onClick={() => {
const newDate = new Date(selectedDate);
newDate.setDate(newDate.getDate() + 1);
setSelectedDate(newDate);
}}>
<ChevronRight size={18} />
</Button>
</div>
</div>
{/* Lista de Agendamentos */}
<Card className="p-6">
{filteredAppointments.length > 0 ? (
<div className="space-y-3">
{filteredAppointments.map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
const customer = users.find((u) => u.id === a.customerId);
const aptDate = new Date(a.date.replace(' ', 'T'));
const timeStr = aptDate.toLocaleTimeString('pt-PT', { hour: '2-digit', minute: '2-digit' });
const dateStr = aptDate.toLocaleDateString('pt-PT', { day: 'numeric', month: 'long', year: 'numeric' });
return (
<div
key={a.id}
className="flex items-center justify-between p-4 border border-slate-200 rounded-lg hover:border-indigo-300 hover:shadow-sm transition-all"
>
<div className="flex-1 grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<p className="text-xs text-slate-500 mb-1">Cliente</p>
<p className="font-semibold text-slate-900">{customer?.name || 'Cliente'}</p>
<p className="text-xs text-slate-500">{customer?.email || ''}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Serviço</p>
<p className="font-semibold text-slate-900">{svc?.name ?? 'Serviço'}</p>
<p className="text-xs text-slate-500">{barber?.name ?? 'Barbeiro'}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Data e Hora</p>
<p className="font-semibold text-slate-900">{dateStr}</p>
<p className="text-xs text-slate-500">{timeStr}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Status</p>
<div className="flex items-center gap-2">
<Badge
color={
a.status === 'pendente'
? 'amber'
: a.status === 'confirmado'
? 'green'
: a.status === 'concluido'
? 'green'
: 'red'
}
>
{a.status === 'pendente'
? 'Pendente'
: a.status === 'confirmado'
? 'Confirmado'
: a.status === 'concluido'
? 'Concluído'
: 'Cancelado'}
</Badge>
<p className="text-sm font-semibold text-slate-900">{currency(a.total)}</p>
</div>
</div>
</div>
<div className="ml-4">
<select
className="text-sm border border-slate-300 rounded-lg px-3 py-2 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/30"
value={a.status}
onChange={(e) => updateAppointmentStatus(a.id, e.target.value as any)}
>
{['pendente', 'confirmado', 'concluido', 'cancelado'].map((s) => (
<option key={s} value={s}>
{s === 'pendente'
? 'Pendente'
: s === 'confirmado'
? 'Confirmado'
: s === 'concluido'
? 'Concluído'
: 'Cancelado'}
</option>
))}
</select>
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-16">
<Calendar size={64} className="mx-auto text-indigo-300 mb-4" />
<p className="text-lg font-semibold text-slate-900 mb-2">Sem reservas</p>
<p className="text-sm text-slate-600 max-w-md mx-auto">
Ambas as suas reservas online e manuais aparecerão aqui
</p>
</div>
)}
</Card>
{/* Secção de Pedidos Pendentes */}
<Card className="p-6 border-amber-200">
<div className="flex items-center gap-2 mb-4 pb-4 border-b border-slate-100">
<Clock className="text-amber-500" size={20} />
<h3 className="font-bold text-slate-900">Aguardam Aprovação</h3>
<Badge color="slate" variant="soft" className="ml-auto">{pendingAppts}</Badge>
</div>
)}
{shopAppointments.filter(a => a.status === 'pendente').length > 0 ? (
<div className="space-y-3">
{shopAppointments.filter(a => a.status === 'pendente').map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
const customer = users.find((u) => u.id === a.customerId);
const aptDate = new Date(a.date.replace(' ', 'T'));
{/* Calendar View */}
{appointmentView === 'calendar' && (
<Card className="p-6">
<CalendarWeekView
week={currentWeek}
appointments={shopAppointments}
shop={shop}
onWeekChange={setCurrentWeek}
onStatusChange={updateAppointmentStatus}
/>
</Card>
)}
return (
<div key={a.id} className="flex flex-col sm:flex-row sm:items-center justify-between p-4 bg-amber-50/50 border border-amber-100 rounded-lg gap-4">
<div className="flex-1 grid grid-cols-1 sm:grid-cols-3 gap-4">
<div>
<p className="text-xs text-slate-500 mb-1">Cliente</p>
<p className="font-semibold text-slate-900">{customer?.name || 'Cliente'}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Serviço</p>
<p className="font-semibold text-slate-900">{svc?.name ?? 'Serviço'}</p>
<p className="text-xs text-slate-500">com {barber?.name ?? 'Barbeiro'}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Data / Hora</p>
<p className="font-semibold text-amber-700">
{aptDate.toLocaleDateString('pt-PT', { day: 'numeric', month: 'short' })} às {aptDate.toLocaleTimeString('pt-PT', { hour: '2-digit', minute: '2-digit' })}
</p>
</div>
</div>
<div className="flex items-center gap-2 mt-2 sm:mt-0">
<Button
variant="outline"
className="text-red-600 border-red-200 hover:bg-red-50 hover:border-red-300"
onClick={() => updateAppointmentStatus(a.id, 'cancelado')}
>
Recusar
</Button>
<Button
className="bg-amber-500 hover:bg-amber-600 text-white"
onClick={() => updateAppointmentStatus(a.id, 'confirmado')}
>
Aceitar
</Button>
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-8">
<CheckCircle2 size={40} className="mx-auto text-slate-300 mb-2" />
<p className="text-slate-500 text-sm">Não pedidos pendentes no momento.</p>
</div>
)}
</Card>
{/* Secção de Pedidos Confirmados */}
<Card className="p-6">
<div className="flex items-center gap-2 mb-4 pb-4 border-b border-slate-100">
<Calendar className="text-green-500" size={20} />
<h3 className="font-bold text-slate-900">Agendamentos Aprovados</h3>
<Badge color="slate" variant="soft" className="ml-auto">{confirmedAppts}</Badge>
</div>
{shopAppointments.filter(a => a.status === 'confirmado').length > 0 ? (
<div className="space-y-3">
{shopAppointments.filter(a => a.status === 'confirmado').map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
const customer = users.find((u) => u.id === a.customerId);
const aptDate = new Date(a.date.replace(' ', 'T'));
return (
<div key={a.id} className="flex flex-col sm:flex-row sm:items-center justify-between p-4 border border-slate-200 rounded-lg gap-4">
<div className="flex-1 grid grid-cols-1 sm:grid-cols-3 gap-4">
<div>
<p className="text-xs text-slate-500 mb-1">Cliente</p>
<p className="font-semibold text-slate-900">{customer?.name || 'Cliente'}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Serviço</p>
<p className="font-semibold text-slate-900">{svc?.name ?? 'Serviço'}</p>
<p className="text-xs text-slate-500">com {barber?.name ?? 'Barbeiro'}</p>
</div>
<div>
<p className="text-xs text-slate-500 mb-1">Data / Hora</p>
<p className="font-semibold text-slate-900">
{aptDate.toLocaleDateString('pt-PT', { day: 'numeric', month: 'short' })} às {aptDate.toLocaleTimeString('pt-PT', { hour: '2-digit', minute: '2-digit' })}
</p>
</div>
</div>
<div className="flex items-center gap-2 mt-2 sm:mt-0">
<Button
variant="outline"
className="text-red-600 border-red-200 hover:bg-red-50 hover:border-red-300"
onClick={() => {
if (window.confirm('Tem a certeza que deseja cancelar esta marcação?')) {
updateAppointmentStatus(a.id, 'cancelado');
}
}}
>
Cancelar
</Button>
<Button
className="bg-green-600 hover:bg-green-700 text-white"
onClick={() => updateAppointmentStatus(a.id, 'concluido')}
>
Concluir Serviço
</Button>
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-8">
<Calendar size={40} className="mx-auto text-slate-300 mb-2" />
<p className="text-slate-500 text-sm">Próximos serviços irão aparecer aqui.</p>
</div>
)}
</Card>
</div>
)}
{activeTab === 'history' && (
<Card className="p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-bold text-slate-900">Histórico de Agendamentos</h2>
<Badge color="slate" variant="soft">{completedAppointments.length} concluídos</Badge>
</div>
<div className="space-y-3">
{completedAppointments.length > 0 ? (
completedAppointments.map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
return (
<div key={a.id} className="flex items-center justify-between p-4 border border-slate-200 rounded-lg bg-slate-50/50">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<p className="font-bold text-slate-900">{svc?.name ?? 'Serviço'}</p>
<Badge color="green" variant="soft">Concluído</Badge>
{activeTab === 'history' && (() => {
// O histórico agora compreende marcacões permanentemente finalizadas (Cancelados e Concluídos)
const historyAppointments = allShopAppointments.filter(a => a.status === 'concluido' || a.status === 'cancelado');
return (
<Card className="p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-bold text-slate-900">Histórico de Agendamentos</h2>
<Badge color="slate" variant="soft">{historyAppointments.length} registos</Badge>
</div>
<div className="space-y-3">
{historyAppointments.length > 0 ? (
historyAppointments.map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
const customer = users.find((u) => u.id === a.customerId);
const aptDate = new Date(a.date.replace(' ', 'T'));
return (
<div key={a.id} className="flex items-center justify-between p-4 border border-slate-200 rounded-lg bg-slate-50/50">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<p className="font-bold text-slate-900">{svc?.name ?? 'Serviço'}</p>
<Badge color={a.status === 'concluido' ? 'green' : 'red'} variant="soft">
{a.status === 'concluido' ? 'Concluído' : 'Cancelado'}
</Badge>
</div>
<p className="text-sm text-slate-600">
{customer?.name || 'Cliente'} c/ {barber?.name ?? 'Barbeiro'} ·
{aptDate.toLocaleDateString('pt-PT', { day: 'numeric', month: 'short' })}
</p>
<p className="text-xs text-slate-500 mt-1">{currency(a.total)}</p>
</div>
<p className="text-sm text-slate-600">{barber?.name ?? 'Barbeiro'} · {a.date}</p>
<p className="text-xs text-slate-500 mt-1">{currency(a.total)}</p>
</div>
</div>
);
})
) : (
<div className="text-center py-12">
<History size={48} className="mx-auto text-slate-300 mb-3" />
<p className="text-slate-600 font-medium">Nenhum agendamento concluído no período</p>
<p className="text-sm text-slate-500 mt-1">Os agendamentos concluídos aparecerão aqui</p>
</div>
)}
</div>
</Card>
)}
);
})
) : (
<div className="text-center py-12">
<History size={48} className="mx-auto text-slate-300 mb-3" />
<p className="text-slate-600 font-medium">Nenhum registo no período selecionado</p>
<p className="text-sm text-slate-500 mt-1">Os agendamentos cancelados ou concluídos aparecerão aqui.</p>
</div>
)}
</div>
</Card>
);
})()}
{activeTab === 'orders' && (
<Card className="p-6">