gohorsejobs/frontend/src/app/dashboard/empresa/relatorios/page.tsx
Tiago Yamamoto 1c7ef95c1a first commit
2025-12-09 19:04:48 -03:00

441 lines
15 KiB
TypeScript

"use client";
import { useState } from "react";
import { DashboardHeader } from "@/components/dashboard-header";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
TrendingUp,
TrendingDown,
Users,
Briefcase,
Eye,
UserCheck,
Clock,
Target,
Download,
Calendar,
} from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Progress } from "@/components/ui/progress";
export default function CompanyReportsPage() {
const [period, setPeriod] = useState("30");
const stats = [
{
title: "Total de Vagas Ativas",
value: "8",
change: "+2",
changeType: "positive" as const,
icon: Briefcase,
description: "2 novas vagas este mês",
},
{
title: "Candidaturas Recebidas",
value: "156",
change: "+23%",
changeType: "positive" as const,
icon: Users,
description: "vs. mês anterior",
},
{
title: "Taxa de Conversão",
value: "12.8%",
change: "+3.2%",
changeType: "positive" as const,
icon: Target,
description: "candidatos contratados",
},
{
title: "Tempo Médio de Contratação",
value: "18 dias",
change: "-3 dias",
changeType: "positive" as const,
icon: Clock,
description: "vs. mês anterior",
},
];
const jobPerformance = [
{
title: "Desenvolvedor Full Stack Sênior",
views: 234,
applications: 45,
conversionRate: 19.2,
status: "Ativa",
daysOpen: 12,
},
{
title: "Designer UX/UI",
views: 189,
applications: 38,
conversionRate: 20.1,
status: "Ativa",
daysOpen: 8,
},
{
title: "Product Manager",
views: 167,
applications: 29,
conversionRate: 17.4,
status: "Ativa",
daysOpen: 15,
},
{
title: "DevOps Engineer",
views: 145,
applications: 22,
conversionRate: 15.2,
status: "Pausada",
daysOpen: 20,
},
{
title: "Data Scientist",
views: 198,
applications: 34,
conversionRate: 17.2,
status: "Ativa",
daysOpen: 10,
},
];
const funnelData = [
{
stage: "Visualizações",
count: 1250,
percentage: 100,
color: "bg-blue-500",
},
{
stage: "Candidaturas",
count: 156,
percentage: 12.5,
color: "bg-green-500",
},
{ stage: "Em Análise", count: 89, percentage: 7.1, color: "bg-yellow-500" },
{
stage: "Entrevistas",
count: 34,
percentage: 2.7,
color: "bg-orange-500",
},
{
stage: "Contratados",
count: 20,
percentage: 1.6,
color: "bg-purple-500",
},
];
const topSources = [
{ source: "LinkedIn", applications: 67, percentage: 43 },
{ source: "Busca Orgânica", applications: 45, percentage: 29 },
{ source: "Indeed", applications: 28, percentage: 18 },
{ source: "Indicações", applications: 16, percentage: 10 },
];
return (
<div className="min-h-screen bg-background">
<DashboardHeader />
<main className="container mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8">
<div className="max-w-7xl mx-auto space-y-6">
{/* Header */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div>
<h1 className="text-2xl sm:text-3xl font-bold text-foreground mb-2">
Relatórios e Analytics
</h1>
<p className="text-muted-foreground">
Acompanhe o desempenho das suas vagas
</p>
</div>
<div className="flex flex-col sm:flex-row gap-2">
<Select value={period} onValueChange={setPeriod}>
<SelectTrigger className="w-full sm:w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="7">Últimos 7 dias</SelectItem>
<SelectItem value="30">Últimos 30 dias</SelectItem>
<SelectItem value="90">Últimos 90 dias</SelectItem>
<SelectItem value="365">Último ano</SelectItem>
</SelectContent>
</Select>
<Button variant="outline" className="gap-2">
<Download className="h-4 w-4" />
Exportar
</Button>
</div>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{stats.map((stat, index) => {
const Icon = stat.icon;
return (
<Card key={index}>
<CardContent className="p-6">
<div className="flex items-start justify-between mb-4">
<div className="p-2 bg-primary/10 rounded-lg">
<Icon className="h-5 w-5 text-primary" />
</div>
<Badge
variant={
stat.changeType === "positive"
? "default"
: "destructive"
}
>
{stat.changeType === "positive" ? (
<TrendingUp className="h-3 w-3 mr-1" />
) : (
<TrendingDown className="h-3 w-3 mr-1" />
)}
{stat.change}
</Badge>
</div>
<h3 className="text-2xl font-bold mb-1">{stat.value}</h3>
<p className="text-sm font-medium text-foreground mb-1">
{stat.title}
</p>
<p className="text-xs text-muted-foreground">
{stat.description}
</p>
</CardContent>
</Card>
);
})}
</div>
{/* Funnel */}
<Card>
<CardHeader>
<CardTitle>Funil de Conversão</CardTitle>
<CardDescription>
Acompanhe o fluxo de candidatos em cada etapa do processo
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{funnelData.map((item, index) => (
<div key={index} className="space-y-2">
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2">
<div className={`h-3 w-3 rounded-full ${item.color}`} />
<span className="font-medium">{item.stage}</span>
</div>
<div className="flex items-center gap-4">
<span className="text-muted-foreground">
{item.count} candidatos
</span>
<span className="font-medium min-w-[60px] text-right">
{item.percentage}%
</span>
</div>
</div>
<Progress value={item.percentage} className="h-2" />
</div>
))}
</div>
<div className="mt-6 p-4 bg-muted/50 rounded-lg">
<div className="flex items-start gap-2">
<Target className="h-5 w-5 text-primary mt-0.5" />
<div>
<p className="font-medium text-sm mb-1">Taxa de Sucesso</p>
<p className="text-sm text-muted-foreground">
1.6% dos visitantes se tornam contratações. A média do
mercado é 1.2%.
</p>
</div>
</div>
</div>
</CardContent>
</Card>
<div className="grid lg:grid-cols-2 gap-6">
{/* Job Performance */}
<Card>
<CardHeader>
<CardTitle>Desempenho por Vaga</CardTitle>
<CardDescription>
Métricas das vagas mais visualizadas
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{jobPerformance.map((job, index) => (
<div
key={index}
className="p-4 border rounded-lg space-y-3"
>
<div className="flex items-start justify-between gap-2">
<div className="flex-1 min-w-0">
<h4 className="font-medium text-sm mb-1 truncate">
{job.title}
</h4>
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Badge
variant={
job.status === "Ativa" ? "default" : "secondary"
}
className="text-xs"
>
{job.status}
</Badge>
<span className="flex items-center gap-1">
<Calendar className="h-3 w-3" />
{job.daysOpen} dias
</span>
</div>
</div>
</div>
<div className="grid grid-cols-3 gap-2">
<div>
<div className="flex items-center gap-1 text-muted-foreground mb-1">
<Eye className="h-3 w-3" />
<span className="text-xs">Visualizações</span>
</div>
<p className="text-lg font-semibold">{job.views}</p>
</div>
<div>
<div className="flex items-center gap-1 text-muted-foreground mb-1">
<Users className="h-3 w-3" />
<span className="text-xs">Candidaturas</span>
</div>
<p className="text-lg font-semibold">
{job.applications}
</p>
</div>
<div>
<div className="flex items-center gap-1 text-muted-foreground mb-1">
<Target className="h-3 w-3" />
<span className="text-xs">Taxa</span>
</div>
<p className="text-lg font-semibold">
{job.conversionRate}%
</p>
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* Top Sources */}
<Card>
<CardHeader>
<CardTitle>Principais Fontes</CardTitle>
<CardDescription>De onde vêm suas candidaturas</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{topSources.map((source, index) => (
<div key={index} className="space-y-2">
<div className="flex items-center justify-between text-sm">
<span className="font-medium">{source.source}</span>
<div className="flex items-center gap-4">
<span className="text-muted-foreground">
{source.applications} candidaturas
</span>
<span className="font-medium min-w-[50px] text-right">
{source.percentage}%
</span>
</div>
</div>
<Progress value={source.percentage} className="h-2" />
</div>
))}
</div>
<div className="mt-6 p-4 bg-muted/50 rounded-lg">
<p className="text-sm text-muted-foreground">
<strong className="text-foreground">LinkedIn</strong> é sua
fonte mais efetiva, gerando 43% de todas as candidaturas.
</p>
</div>
</CardContent>
</Card>
</div>
{/* Time to Hire Chart */}
<Card>
<CardHeader>
<CardTitle>Tempo de Contratação por Cargo</CardTitle>
<CardDescription>
Tempo médio desde a publicação até a contratação
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{[
{ role: "Desenvolvedor Full Stack", days: 15, maxDays: 30 },
{ role: "Designer UX/UI", days: 12, maxDays: 30 },
{ role: "Product Manager", days: 22, maxDays: 30 },
{ role: "DevOps Engineer", days: 18, maxDays: 30 },
{ role: "Data Scientist", days: 20, maxDays: 30 },
].map((item, index) => (
<div key={index} className="space-y-2">
<div className="flex items-center justify-between text-sm">
<span className="font-medium">{item.role}</span>
<span className="text-muted-foreground">
{item.days} dias
</span>
</div>
<Progress
value={(item.days / item.maxDays) * 100}
className="h-2"
/>
</div>
))}
</div>
<div className="mt-6 grid grid-cols-2 gap-4">
<div className="p-4 bg-green-500/10 border border-green-500/20 rounded-lg">
<div className="flex items-center gap-2 mb-1">
<Clock className="h-4 w-4 text-green-600" />
<span className="text-sm font-medium">Mais Rápido</span>
</div>
<p className="text-2xl font-bold">12 dias</p>
<p className="text-xs text-muted-foreground">
Designer UX/UI
</p>
</div>
<div className="p-4 bg-orange-500/10 border border-orange-500/20 rounded-lg">
<div className="flex items-center gap-2 mb-1">
<Clock className="h-4 w-4 text-orange-600" />
<span className="text-sm font-medium">Mais Lento</span>
</div>
<p className="text-2xl font-bold">22 dias</p>
<p className="text-xs text-muted-foreground">
Product Manager
</p>
</div>
</div>
</CardContent>
</Card>
</div>
</main>
</div>
);
}