/ components / jobs / KanbanColumn.tsx
KanbanColumn.tsx
  1  'use client';
  2  
  3  import { Bookmark, Send, Users, Trophy, XCircle, MinusCircle, type LucideIcon } from 'lucide-react';
  4  import { useTranslation } from '@/lib/i18n';
  5  import type { JobApplication, JobStatus } from '@/lib/types';
  6  import JobCard from './JobCard';
  7  
  8  interface KanbanColumnProps {
  9    status: JobStatus;
 10    label: string;
 11    color: string;
 12    icon: string;
 13    jobs: JobApplication[];
 14    onCardClick: (job: JobApplication) => void;
 15    onDragStart: (e: React.DragEvent, jobId: string) => void;
 16    onDragOver: (e: React.DragEvent) => void;
 17    onDrop: (e: React.DragEvent) => void;
 18    isDragOver: boolean;
 19    draggingJobId: string | null;
 20  }
 21  
 22  const ICON_MAP: Record<string, LucideIcon> = {
 23    Bookmark,
 24    Send,
 25    Users,
 26    Trophy,
 27    XCircle,
 28    MinusCircle,
 29  };
 30  
 31  export default function KanbanColumn({
 32    status,
 33    label,
 34    color,
 35    icon,
 36    jobs,
 37    onCardClick,
 38    onDragStart,
 39    onDragOver,
 40    onDrop,
 41    isDragOver,
 42    draggingJobId,
 43  }: KanbanColumnProps) {
 44    const { t } = useTranslation();
 45    const IconComponent = ICON_MAP[icon];
 46  
 47    return (
 48      <div className="min-w-[220px] w-full max-w-[300px] flex-shrink-0">
 49        {/* Column header */}
 50        <div className="flex items-center gap-2 mb-3 px-1">
 51          {IconComponent && (
 52            <IconComponent size={14} className="flex-shrink-0" style={{ color }} />
 53          )}
 54          <span
 55            className="inline-block w-2.5 h-2.5 rounded-full flex-shrink-0"
 56            style={{ backgroundColor: color }}
 57          />
 58          <span className="text-sm font-semibold text-text-primary truncate">
 59            {label}
 60          </span>
 61          <span
 62            className="text-[11px] font-medium px-2 py-0.5 rounded-full flex-shrink-0"
 63            style={{
 64              backgroundColor: `${color}14`,
 65              color,
 66            }}
 67          >
 68            {jobs.length}
 69          </span>
 70        </div>
 71  
 72        {/* Column body */}
 73        <div
 74          onDragOver={onDragOver}
 75          onDrop={onDrop}
 76          className={`flex flex-col gap-2 p-2 rounded-xl min-h-[200px] transition-all duration-200 ${
 77            isDragOver
 78              ? 'border-2 border-dashed border-orange-400 bg-orange-50/50'
 79              : 'border-2 border-dashed border-transparent bg-black/[0.02]'
 80          }`}
 81        >
 82          {jobs.map((job) => (
 83            <JobCard
 84              key={job.id}
 85              job={job}
 86              onClick={() => onCardClick(job)}
 87              onDragStart={onDragStart}
 88              isDragging={draggingJobId === job.id}
 89            />
 90          ))}
 91  
 92          {jobs.length === 0 && !isDragOver && (
 93            <div className="flex items-center justify-center h-24 text-xs text-text-tertiary">
 94              {t('jobs.emptyColumn')}
 95            </div>
 96          )}
 97        </div>
 98      </div>
 99    );
100  }