import React, { useState } from 'react'; import { Deal, DealStage } from '../../../entities/crm/deal'; import { Contact } from '../../../entities/crm/contact'; import { Company } from '../../../entities/crm/company'; import { Button } from '../../../shared/ui/Button'; import { formatCurrencyMinor } from '../../../shared/lib/currency'; import { DEAL_STAGES } from '../constants'; import { Search, Plus, ArrowRight, Building } from 'lucide-react'; export interface CrmKanbanViewProps { deals: Deal[]; contacts: Contact[]; companies: Company[]; search: string; onSearchChange: (value: string) => void; onAddDeal: () => void; onStageChange: (dealId: string, nextStage: DealStage) => Promise | void; } export const CrmKanbanView: React.FC = ({ deals, contacts, companies, search, onSearchChange, onAddDeal, onStageChange, }) => { const [draggedDealId, setDraggedDealId] = useState(null); const handleDragStart = (e: React.DragEvent, dealId: string) => { e.dataTransfer.setData('text/plain', dealId); setDraggedDealId(dealId); }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); }; const handleDrop = async (e: React.DragEvent, targetStage: DealStage) => { e.preventDefault(); const dealId = e.dataTransfer.getData('text/plain') || draggedDealId; if (dealId) { await onStageChange(dealId, targetStage); } setDraggedDealId(null); }; return (
onSearchChange(e.target.value)} placeholder="Поиск по сделкам..." className="w-full pl-8 pr-3 py-1.5 text-xs bg-krona-surface border border-krona-border rounded-lg text-krona-primary focus:outline-none focus:border-krona-green" />
{DEAL_STAGES.map((col) => { const colDeals = deals.filter( (d) => d.stage === col.key && (d.title.toLowerCase().includes(search.toLowerCase()) || !search) ); const colTotalMinor = colDeals.reduce((sum, d) => sum + d.amount.minor, 0); return (
handleDrop(e, col.key)} className={`bg-krona-surface/70 border rounded-xl p-2.5 flex flex-col min-w-[200px] max-h-[750px] shadow-krona-soft transition-all ${col.color}`} >
{col.label}
{formatCurrencyMinor(colTotalMinor)}
{colDeals.length}
{colDeals.map((deal) => { const contact = contacts.find((c) => c.id === deal.contactId); const company = companies.find((c) => c.id === deal.companyId); const nextStageIdx = DEAL_STAGES.findIndex((s) => s.key === deal.stage) + 1; const nextStage = DEAL_STAGES[nextStageIdx]?.key; return (
handleDragStart(e, deal.id)} className="bg-krona-workspace border border-krona-border hover:border-krona-green/60 p-2.5 rounded-lg text-xs space-y-2 shadow-xs cursor-grab active:cursor-grabbing transition-all" >
{deal.title}
{formatCurrencyMinor(deal.amount.minor)} {deal.probability}% вер.
{(contact || company) && (
{company?.name || `${contact?.firstName} ${contact?.lastName}`}
)} {/* Quick stage transition button */} {nextStage && deal.stage !== 'won' && deal.stage !== 'lost' && ( )}
); })} {colDeals.length === 0 && (
Пусто
)}
); })}
); };