Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
63
src/components/interests/pipeline-column.tsx
Normal file
63
src/components/interests/pipeline-column.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
'use client';
|
||||
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
||||
|
||||
import { PipelineCard } from '@/components/interests/pipeline-card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
interface ColumnItem {
|
||||
id: string;
|
||||
clientName: string | null;
|
||||
berthMooringNumber: string | null;
|
||||
leadCategory: string | null;
|
||||
updatedAt: string | Date;
|
||||
}
|
||||
|
||||
interface PipelineColumnProps {
|
||||
stage: string;
|
||||
label: string;
|
||||
items: ColumnItem[];
|
||||
}
|
||||
|
||||
export function PipelineColumn({ stage, label, items }: PipelineColumnProps) {
|
||||
const { setNodeRef, isOver } = useDroppable({ id: stage });
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
className={`flex flex-col gap-2 min-w-[220px] w-[220px] flex-shrink-0 bg-muted/40 rounded-lg p-3 transition-colors ${
|
||||
isOver ? 'bg-muted/70 ring-2 ring-primary/30' : ''
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="text-sm font-semibold capitalize">{label}</span>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{items.length}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2 overflow-y-auto max-h-[calc(100vh-220px)]">
|
||||
<SortableContext
|
||||
items={items.map((i) => i.id)}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<PipelineCard
|
||||
key={item.id}
|
||||
id={item.id}
|
||||
clientName={item.clientName}
|
||||
berthMooringNumber={item.berthMooringNumber}
|
||||
leadCategory={item.leadCategory}
|
||||
updatedAt={item.updatedAt}
|
||||
/>
|
||||
))}
|
||||
</SortableContext>
|
||||
|
||||
{items.length === 0 && (
|
||||
<div className="text-center py-6 text-xs text-muted-foreground">Empty</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user