237 lines
12 KiB
TypeScript
237 lines
12 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { getUser } from '@/lib/auth';
|
|
import {
|
|
RocketLaunchIcon,
|
|
ChartBarIcon,
|
|
BriefcaseIcon,
|
|
LifebuoyIcon,
|
|
CreditCardIcon,
|
|
DocumentTextIcon,
|
|
FolderIcon,
|
|
ShareIcon,
|
|
ArrowTrendingUpIcon,
|
|
ArrowTrendingDownIcon,
|
|
CheckCircleIcon,
|
|
ClockIcon,
|
|
} from '@heroicons/react/24/outline';
|
|
|
|
export default function DashboardPage() {
|
|
const [userName, setUserName] = useState('');
|
|
const [greeting, setGreeting] = useState('');
|
|
|
|
useEffect(() => {
|
|
const user = getUser();
|
|
if (user) {
|
|
setUserName(user.name.split(' ')[0]); // Primeiro nome
|
|
}
|
|
|
|
const hour = new Date().getHours();
|
|
if (hour >= 5 && hour < 12) setGreeting('Bom dia');
|
|
else if (hour >= 12 && hour < 18) setGreeting('Boa tarde');
|
|
else setGreeting('Boa noite');
|
|
}, []);
|
|
|
|
const overviewStats = [
|
|
{ name: 'Receita Total (Mês)', value: 'R$ 124.500', change: '+12%', changeType: 'increase', icon: ChartBarIcon, color: 'green' },
|
|
{ name: 'Novos Leads', value: '45', change: '+5%', changeType: 'increase', icon: RocketLaunchIcon, color: 'blue' },
|
|
{ name: 'Projetos Ativos', value: '12', change: '-1', changeType: 'decrease', icon: BriefcaseIcon, color: 'purple' },
|
|
{ name: 'Chamados Abertos', value: '3', change: '-2', changeType: 'decrease', icon: LifebuoyIcon, color: 'orange' },
|
|
];
|
|
|
|
const modules = [
|
|
{
|
|
title: 'CRM & Vendas',
|
|
icon: RocketLaunchIcon,
|
|
color: 'blue',
|
|
stats: [
|
|
{ label: 'Propostas Enviadas', value: '8' },
|
|
{ label: 'Aguardando Aprovação', value: '3' },
|
|
{ label: 'Taxa de Conversão', value: '24%' },
|
|
]
|
|
},
|
|
{
|
|
title: 'Financeiro & ERP',
|
|
icon: ChartBarIcon,
|
|
color: 'green',
|
|
stats: [
|
|
{ label: 'A Receber', value: 'R$ 45.200' },
|
|
{ label: 'A Pagar', value: 'R$ 12.800' },
|
|
{ label: 'Fluxo de Caixa', value: 'Positivo' },
|
|
]
|
|
},
|
|
{
|
|
title: 'Projetos & Tarefas',
|
|
icon: BriefcaseIcon,
|
|
color: 'purple',
|
|
stats: [
|
|
{ label: 'Em Andamento', value: '12' },
|
|
{ label: 'Atrasados', value: '1' },
|
|
{ label: 'Concluídos (Mês)', value: '4' },
|
|
]
|
|
},
|
|
{
|
|
title: 'Helpdesk',
|
|
icon: LifebuoyIcon,
|
|
color: 'orange',
|
|
stats: [
|
|
{ label: 'Novos Chamados', value: '3' },
|
|
{ label: 'Tempo Médio Resposta', value: '2h' },
|
|
{ label: 'Satisfação', value: '4.8/5' },
|
|
]
|
|
},
|
|
{
|
|
title: 'Documentos & Contratos',
|
|
icon: DocumentTextIcon,
|
|
color: 'indigo',
|
|
stats: [
|
|
{ label: 'Contratos Ativos', value: '28' },
|
|
{ label: 'A Vencer (30 dias)', value: '2' },
|
|
{ label: 'Docs Armazenados', value: '1.2GB' },
|
|
]
|
|
},
|
|
{
|
|
title: 'Redes Sociais',
|
|
icon: ShareIcon,
|
|
color: 'pink',
|
|
stats: [
|
|
{ label: 'Posts Agendados', value: '14' },
|
|
{ label: 'Engajamento', value: '+8.5%' },
|
|
{ label: 'Novos Seguidores', value: '120' },
|
|
]
|
|
}
|
|
];
|
|
|
|
return (
|
|
<div className="p-6 h-full overflow-auto">
|
|
<div className="space-y-8">
|
|
{/* Header Personalizado */}
|
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
<div>
|
|
<h1 className="text-2xl font-heading font-bold text-gray-900 dark:text-white">
|
|
{greeting}, {userName || 'Administrador'}! 👋
|
|
</h1>
|
|
<p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
|
Aqui está o resumo da sua agência hoje. Tudo parece estar sob controle.
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-xs font-medium px-3 py-1 rounded-full bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 border border-green-200 dark:border-green-800 flex items-center gap-1">
|
|
<span className="w-2 h-2 rounded-full bg-green-500 animate-pulse"></span>
|
|
Sistema Operacional
|
|
</span>
|
|
<span className="text-xs text-gray-500 dark:text-gray-400">
|
|
{new Date().toLocaleDateString('pt-BR', { weekday: 'long', day: 'numeric', month: 'long' })}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Top Stats */}
|
|
<div>
|
|
{/* Mobile: Scroll Horizontal */}
|
|
<div className="md:hidden overflow-x-auto scrollbar-hide">
|
|
<div className="flex gap-4 min-w-max">
|
|
{overviewStats.map((stat) => {
|
|
const Icon = stat.icon;
|
|
return (
|
|
<div
|
|
key={stat.name}
|
|
className="relative overflow-hidden rounded-xl bg-white dark:bg-zinc-900 p-4 border border-gray-200 dark:border-zinc-800 shadow-sm w-[280px] flex-shrink-0"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<div className={`rounded-lg p-2 bg-${stat.color}-50 dark:bg-${stat.color}-900/20`}>
|
|
<Icon className={`h-6 w-6 text-${stat.color}-600 dark:text-${stat.color}-400`} />
|
|
</div>
|
|
<div className={`flex items-baseline text-sm font-semibold ${stat.changeType === 'increase' ? 'text-green-600' : 'text-red-600'
|
|
}`}>
|
|
{stat.changeType === 'increase' ? (
|
|
<ArrowTrendingUpIcon className="h-4 w-4 mr-1" />
|
|
) : (
|
|
<ArrowTrendingDownIcon className="h-4 w-4 mr-1" />
|
|
)}
|
|
{stat.change}
|
|
</div>
|
|
</div>
|
|
<div className="mt-4">
|
|
<p className="text-sm font-medium text-gray-500 dark:text-gray-400">{stat.name}</p>
|
|
<p className="text-2xl font-bold text-gray-900 dark:text-white">{stat.value}</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Desktop: Grid */}
|
|
<div className="hidden md:grid md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{overviewStats.map((stat) => {
|
|
const Icon = stat.icon;
|
|
return (
|
|
<div
|
|
key={stat.name}
|
|
className="relative overflow-hidden rounded-xl bg-white dark:bg-zinc-900 p-4 border border-gray-200 dark:border-zinc-800 shadow-sm"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<div className={`rounded-lg p-2 bg-${stat.color}-50 dark:bg-${stat.color}-900/20`}>
|
|
<Icon className={`h-6 w-6 text-${stat.color}-600 dark:text-${stat.color}-400`} />
|
|
</div>
|
|
<div className={`flex items-baseline text-sm font-semibold ${stat.changeType === 'increase' ? 'text-green-600' : 'text-red-600'
|
|
}`}>
|
|
{stat.changeType === 'increase' ? (
|
|
<ArrowTrendingUpIcon className="h-4 w-4 mr-1" />
|
|
) : (
|
|
<ArrowTrendingDownIcon className="h-4 w-4 mr-1" />
|
|
)}
|
|
{stat.change}
|
|
</div>
|
|
</div>
|
|
<div className="mt-4">
|
|
<p className="text-sm font-medium text-gray-500 dark:text-gray-400">{stat.name}</p>
|
|
<p className="text-2xl font-bold text-gray-900 dark:text-white">{stat.value}</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Modules Grid */}
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
|
Performance por Módulo
|
|
</h2>
|
|
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
{modules.map((module) => {
|
|
const Icon = module.icon;
|
|
return (
|
|
<div
|
|
key={module.title}
|
|
className="rounded-xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 p-6 hover:border-gray-200 dark:hover:border-zinc-700 transition-colors"
|
|
>
|
|
<div className="flex items-center gap-3 mb-6">
|
|
<div className={`p-2 rounded-lg bg-${module.color}-50 dark:bg-${module.color}-900/20`}>
|
|
<Icon className={`h-5 w-5 text-${module.color}-600 dark:text-${module.color}-400`} />
|
|
</div>
|
|
<h3 className="font-semibold text-gray-900 dark:text-white">
|
|
{module.title}
|
|
</h3>
|
|
</div>
|
|
<div className="space-y-4">
|
|
{module.stats.map((stat, idx) => (
|
|
<div key={idx} className="flex items-center justify-between text-sm">
|
|
<span className="text-gray-500 dark:text-gray-400">{stat.label}</span>
|
|
<span className="font-medium text-gray-900 dark:text-white">{stat.value}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|