'use client' import * as React from 'react' import Link from 'next/link' import { useRouter } from 'next/navigation' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Separator } from '@/components/ui/separator' import { ScrollArea } from '@/components/ui/scroll-area' import { Progress } from '@/components/ui/progress' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog' import { Textarea } from '@/components/ui/textarea' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { ArrowLeft, Edit, Clock, Users, MapPin, Building2, Calendar, AlertTriangle, CheckCircle2, XCircle, Send, RefreshCw, UserPlus, FileText, History, MessageSquare, Briefcase, DollarSign, Target, ChevronRight, Ban, } from 'lucide-react' import { cn } from '@/lib/utils' import { requisitions, auditLog, users, recruiterCapacity } from '@/lib/mock-data' import { STATUS_CONFIG, URGENCY_CONFIG, STAGE_CONFIG, type Requisition, type CandidateStage } from '@/lib/types' import { toast } from 'sonner' function getInitials(name: string): string { return name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2) } function getDaysUntilDeadline(deadline: string): number { const now = new Date() const deadlineDate = new Date(deadline) return Math.ceil((deadlineDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)) } function formatDate(dateString: string): string { return new Date(dateString).toLocaleDateString('es-ES', { day: '2-digit', month: 'long', year: 'numeric', }) } function formatDateTime(dateString: string): string { return new Date(dateString).toLocaleString('es-ES', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } // Status flow visualization component function StatusFlow({ currentStatus }: { currentStatus: Requisition['status'] }) { const steps = [ { key: 'borrador', label: 'Borrador', icon: FileText }, { key: 'pendiente_rrhh', label: 'RR.HH.', icon: Users }, { key: 'pendiente_admin', label: 'Admin', icon: Building2 }, { key: 'reclutando', label: 'Reclutando', icon: Briefcase }, { key: 'cerrado', label: 'Cerrado', icon: CheckCircle2 }, ] const currentIndex = steps.findIndex(s => s.key === currentStatus) const isCancelled = currentStatus === 'cancelado' const isCorrection = currentStatus === 'correccion_requerida' return (
{steps.map((step, index) => { const Icon = step.icon const isCompleted = index < currentIndex && !isCancelled const isCurrent = step.key === currentStatus const isPending = index > currentIndex return (
{isCompleted ? ( ) : isCancelled ? ( ) : ( )}
{step.label}
{index < steps.length - 1 && (
)} ) })}
{isCorrection && (
Corrección requerida - Regresado a solicitante
)}
) } // Recruitment stages component function RecruitmentStages({ currentStage }: { currentStage?: CandidateStage }) { if (!currentStage) return null const stages: CandidateStage[] = ['reclutando', 'primera_entrevista', 'segunda_entrevista', 'referencias', 'examenes_medicos', 'seleccionado'] const currentIndex = stages.indexOf(currentStage) return (
{stages.map((stage, index) => { const config = STAGE_CONFIG[stage] const isCompleted = index < currentIndex const isCurrent = stage === currentStage return (
{isCompleted ? : index + 1}
{config.label}
) })}
) } interface RequisitionDetailPageProps { requisitionId: string } export function RequisitionDetailPage({ requisitionId }: RequisitionDetailPageProps) { const router = useRouter() const [cancelDialogOpen, setCancelDialogOpen] = React.useState(false) const [assignDialogOpen, setAssignDialogOpen] = React.useState(false) const [cancelReason, setCancelReason] = React.useState('') const [selectedRecruiter, setSelectedRecruiter] = React.useState('') const requisition = requisitions.find(r => r.id === requisitionId) if (!requisition) { return (

Requisición no encontrada

La requisición {requisitionId} no existe.

) } const status = STATUS_CONFIG[requisition.status] const urgency = URGENCY_CONFIG[requisition.urgency] const daysLeft = getDaysUntilDeadline(requisition.hardDeadline) const isOverdue = daysLeft < 0 const isAtRisk = daysLeft >= 0 && daysLeft <= 7 const progress = (requisition.vacanciesFilled / requisition.quantity) * 100 const relatedAuditLog = auditLog.filter(log => log.entityId === requisitionId) const recruiters = users.filter(u => u.role === 'reclutador' && u.active) const handleCancel = () => { toast.success('Requisición cancelada', { description: `${requisition.id} ha sido cancelada.`, }) setCancelDialogOpen(false) router.push('/requisiciones') } const handleAssignRecruiter = () => { const recruiter = recruiters.find(r => r.id === selectedRecruiter) toast.success('Reclutador asignado', { description: `${recruiter?.name} ha sido asignado a ${requisition.id}.`, }) setAssignDialogOpen(false) } return (
{/* Header */}

{requisition.id}

{status.label} {urgency.label}

{requisition.positionName} - {requisition.quantity} vacante{requisition.quantity > 1 ? 's' : ''}

{requisition.status === 'borrador' && ( <> )} {requisition.status === 'correccion_requerida' && ( )} {requisition.status === 'reclutando' && !requisition.recruiterId && ( Asignar Reclutador Selecciona el reclutador que gestionará esta requisición.
)} {!['cerrado', 'cancelado'].includes(requisition.status) && ( Cancelar Requisición Esta acción no se puede deshacer. La requisición quedará marcada como cancelada.