'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 { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
import { Separator } from '@/components/ui/separator'
import {
ArrowLeft,
ArrowRight,
Save,
Send,
MapPin,
Building2,
Briefcase,
FileText,
DollarSign,
CheckCircle2,
AlertCircle,
} from 'lucide-react'
import { cn } from '@/lib/utils'
import { countries, cities, departments, positions, currentUser, getCitiesByCountry } from '@/lib/mock-data'
import { toast } from 'sonner'
type FormStep = 'ubicacion' | 'vacante' | 'justificacion' | 'compensacion' | 'revision'
const STEPS: { key: FormStep; label: string; icon: React.ElementType }[] = [
{ key: 'ubicacion', label: 'Ubicación', icon: MapPin },
{ key: 'vacante', label: 'Vacante', icon: Briefcase },
{ key: 'justificacion', label: 'Justificación', icon: FileText },
{ key: 'compensacion', label: 'Compensación', icon: DollarSign },
{ key: 'revision', label: 'Revisión', icon: CheckCircle2 },
]
interface FormData {
countryId: string
cityId: string
departmentId: string
positionId: string
quantity: number
modalidad: 'presencial' | 'remoto' | 'hibrido'
tipoContratacion: 'nuevo' | 'reemplazo' | 'temporal'
justification: string
urgency: 'normal' | 'alta' | 'critica'
salaryPackage: string
budget: string
currency: string
}
function StepIndicator({ currentStep }: { currentStep: FormStep }) {
const currentIndex = STEPS.findIndex(s => s.key === currentStep)
return (
{STEPS.map((step, index) => {
const Icon = step.icon
const isCompleted = index < currentIndex
const isCurrent = step.key === currentStep
return (
{isCompleted ? (
) : (
)}
{step.label}
{index < STEPS.length - 1 && (
)}
)
})}
)
}
export function NewRequisitionPage() {
const router = useRouter()
const [currentStep, setCurrentStep] = React.useState('ubicacion')
const [errors, setErrors] = React.useState>>({})
const [formData, setFormData] = React.useState({
countryId: '',
cityId: '',
departmentId: '',
positionId: '',
quantity: 1,
modalidad: 'presencial',
tipoContratacion: 'nuevo',
justification: '',
urgency: 'normal',
salaryPackage: '',
budget: '',
currency: 'USD',
})
const availableCities = formData.countryId ? getCitiesByCountry(formData.countryId) : []
const updateFormData = (field: keyof FormData, value: string | number) => {
setFormData(prev => ({ ...prev, [field]: value }))
if (errors[field]) {
setErrors(prev => ({ ...prev, [field]: undefined }))
}
// Reset city when country changes
if (field === 'countryId') {
setFormData(prev => ({ ...prev, cityId: '' }))
}
}
const validateStep = (step: FormStep): boolean => {
const newErrors: Partial> = {}
if (step === 'ubicacion') {
if (!formData.countryId) newErrors.countryId = 'Selecciona un país'
if (!formData.cityId) newErrors.cityId = 'Selecciona una ciudad'
if (!formData.departmentId) newErrors.departmentId = 'Selecciona un departamento'
}
if (step === 'vacante') {
if (!formData.positionId) newErrors.positionId = 'Selecciona una posición'
if (formData.quantity < 1) newErrors.quantity = 'La cantidad debe ser al menos 1'
}
if (step === 'justificacion') {
if (!formData.justification.trim()) newErrors.justification = 'La justificación es obligatoria'
if (formData.justification.length < 20) newErrors.justification = 'Proporciona una justificación más detallada (mín. 20 caracteres)'
}
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
const goToNextStep = () => {
if (!validateStep(currentStep)) return
const currentIndex = STEPS.findIndex(s => s.key === currentStep)
if (currentIndex < STEPS.length - 1) {
setCurrentStep(STEPS[currentIndex + 1].key)
}
}
const goToPreviousStep = () => {
const currentIndex = STEPS.findIndex(s => s.key === currentStep)
if (currentIndex > 0) {
setCurrentStep(STEPS[currentIndex - 1].key)
}
}
const handleSaveDraft = () => {
toast.success('Borrador guardado', {
description: 'La requisición se ha guardado como borrador.',
})
}
const handleSubmit = () => {
toast.success('Requisición enviada', {
description: 'La requisición ha sido enviada para aprobación de RR.HH.',
})
router.push('/requisiciones')
}
const selectedCountry = countries.find(c => c.id === formData.countryId)
const selectedCity = cities.find(c => c.id === formData.cityId)
const selectedDepartment = departments.find(d => d.id === formData.departmentId)
const selectedPosition = positions.find(p => p.id === formData.positionId)
return (
{/* Header */}
Nueva Requisición
Completa el formulario para solicitar una nueva vacante
{/* Step Indicator */}
{/* Form Card */}
{/* Step 1: Ubicación */}
{currentStep === 'ubicacion' && (
Ubicación
Define el país, ciudad y departamento de la vacante
{errors.countryId && (
{errors.countryId}
)}
{errors.cityId && (
{errors.cityId}
)}
{errors.departmentId && (
{errors.departmentId}
)}
{/* Requester Info */}
Solicitante
{currentUser.name}
{currentUser.email}
)}
{/* Step 2: Vacante */}
{currentStep === 'vacante' && (
Información de la Vacante
Define la posición, cantidad y tipo de contratación
{errors.positionId && (
{errors.positionId}
)}
updateFormData('quantity', parseInt(e.target.value) || 1)}
className={cn(errors.quantity && 'border-destructive')}
/>
{errors.quantity && (
{errors.quantity}
)}
updateFormData('modalidad', v)}
className="flex gap-4"
>
updateFormData('tipoContratacion', v)}
className="flex gap-4"
>
)}
{/* Step 3: Justificación */}
{currentStep === 'justificacion' && (
Justificación
Explica el motivo de la requisición y su nivel de urgencia
updateFormData('urgency', v)}
className="grid gap-3"
>
Proceso estándar de reclutamiento según SLA definido
Requiere atención prioritaria, impacto operativo significativo
Urgencia máxima, afecta operaciones críticas del negocio
)}
{/* Step 4: Compensación */}
{currentStep === 'compensacion' && (
Compensación
Define el paquete salarial y presupuesto (opcional, visible solo para roles autorizados)
Nota de privacidad
La información de compensación solo será visible para roles autorizados (RR.HH. y Administración).
)}
{/* Step 5: Revisión */}
{currentStep === 'revision' && (
Revisión Final
Verifica que toda la información sea correcta antes de enviar
{/* Location Summary */}
Ubicación
País:
{selectedCountry?.name || '-'}
Ciudad:
{selectedCity?.name || '-'}
Departamento:
{selectedDepartment?.name || '-'}
{/* Vacancy Summary */}
Vacante
Posición:
{selectedPosition?.name || '-'}
Cantidad:
{formData.quantity}
Modalidad:
{formData.modalidad}
Tipo:
{formData.tipoContratacion}
{/* Justification Summary */}
Justificación
Urgencia:
{formData.urgency}
{formData.justification || '-'}
{/* Compensation Summary */}
{(formData.salaryPackage || formData.budget) && (
Compensación
{formData.salaryPackage && (
Paquete:
{formData.salaryPackage}
)}
{formData.budget && (
Presupuesto:
{formData.currency} {parseInt(formData.budget).toLocaleString()}
)}
)}
)}
{/* Navigation Buttons */}
{currentStep !== 'ubicacion' && (
)}
{currentStep !== 'revision' ? (
) : (
)}
)
}