221 lines
6.9 KiB
TypeScript
221 lines
6.9 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { DashboardHeader } from "@/components/dashboard-header";
|
|
import { StatsCard } from "@/components/stats-card";
|
|
import { JobCard } from "@/components/job-card";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Progress } from "@/components/ui/progress";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table";
|
|
import { getCurrentUser } from "@/lib/auth";
|
|
import { mockJobs, mockApplications, mockNotifications } from "@/lib/mock-data";
|
|
import {
|
|
Bell,
|
|
FileText,
|
|
Clock,
|
|
CheckCircle,
|
|
XCircle,
|
|
AlertCircle,
|
|
Edit,
|
|
} from "lucide-react";
|
|
import { motion } from "framer-motion";
|
|
|
|
export default function CandidateDashboard() {
|
|
const router = useRouter();
|
|
const [user, setUser] = useState(getCurrentUser());
|
|
|
|
useEffect(() => {
|
|
const currentUser = getCurrentUser();
|
|
if (!currentUser || currentUser.role !== "candidate") {
|
|
router.push("/login");
|
|
} else {
|
|
setUser(currentUser);
|
|
}
|
|
}, [router]);
|
|
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
|
|
const recommendedJobs = mockJobs.slice(0, 3);
|
|
const unreadNotifications = mockNotifications.filter((n) => !n.read);
|
|
|
|
const getStatusBadge = (status: string) => {
|
|
switch (status) {
|
|
case "pending":
|
|
return (
|
|
<Badge variant="secondary">
|
|
<Clock className="h-3 w-3 mr-1" />
|
|
Em análise
|
|
</Badge>
|
|
);
|
|
case "reviewing":
|
|
return (
|
|
<Badge variant="secondary">
|
|
<AlertCircle className="h-3 w-3 mr-1" />
|
|
Em análise
|
|
</Badge>
|
|
);
|
|
case "interview":
|
|
return (
|
|
<Badge className="bg-blue-500 hover:bg-blue-600">
|
|
<CheckCircle className="h-3 w-3 mr-1" />
|
|
Entrevista
|
|
</Badge>
|
|
);
|
|
case "accepted":
|
|
return (
|
|
<Badge className="bg-green-500 hover:bg-green-600">
|
|
<CheckCircle className="h-3 w-3 mr-1" />
|
|
Aprovado
|
|
</Badge>
|
|
);
|
|
case "rejected":
|
|
return (
|
|
<Badge variant="destructive">
|
|
<XCircle className="h-3 w-3 mr-1" />
|
|
Rejeitado
|
|
</Badge>
|
|
);
|
|
default:
|
|
return <Badge variant="outline">{status}</Badge>;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
<DashboardHeader />
|
|
|
|
<main className="container mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
{/* Profile Summary */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<Card className="mb-8">
|
|
<CardContent className="pt-6">
|
|
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
|
<div className="flex-1">
|
|
<h1 className="text-2xl font-bold mb-2">Olá, {user.name}!</h1>
|
|
<p className="text-muted-foreground">{user.area}</p>
|
|
</div>
|
|
<Button className="cursor-pointer">
|
|
<Edit className="mr-2 h-4 w-4" />
|
|
Editar Perfil
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</motion.div>
|
|
|
|
{/* Stats */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.5, delay: 0.1 }}
|
|
className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"
|
|
>
|
|
<StatsCard
|
|
title="Candidaturas"
|
|
value={mockApplications.length}
|
|
icon={FileText}
|
|
description="Total de vagas aplicadas"
|
|
/>
|
|
<StatsCard
|
|
title="Em processo"
|
|
value={
|
|
mockApplications.filter(
|
|
(a) => a.status === "reviewing" || a.status === "interview"
|
|
).length
|
|
}
|
|
icon={Clock}
|
|
description="Aguardando resposta"
|
|
/>
|
|
<StatsCard
|
|
title="Notificações"
|
|
value={unreadNotifications.length}
|
|
icon={Bell}
|
|
description="Novas atualizações"
|
|
/>
|
|
</motion.div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-1 gap-8">
|
|
{/* Main Content */}
|
|
<div className="space-y-8">
|
|
{/* Recommended Jobs */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.5, delay: 0.2 }}
|
|
>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Vagas recomendadas</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{recommendedJobs.map((job) => (
|
|
<JobCard key={job.id} job={job} />
|
|
))}
|
|
</CardContent>
|
|
</Card>
|
|
</motion.div>
|
|
|
|
{/* Applications */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.5, delay: 0.3 }}
|
|
>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Minhas candidaturas</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Vaga</TableHead>
|
|
<TableHead>Empresa</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead>Data</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{mockApplications.map((application) => (
|
|
<TableRow key={application.id}>
|
|
<TableCell className="font-medium">
|
|
{application.jobTitle}
|
|
</TableCell>
|
|
<TableCell>{application.company}</TableCell>
|
|
<TableCell>
|
|
{getStatusBadge(application.status)}
|
|
</TableCell>
|
|
<TableCell className="text-muted-foreground">
|
|
{new Date(application.appliedAt).toLocaleDateString(
|
|
"pt-BR"
|
|
)}
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|