// CRM — Müşteri İlişkileri Yönetimi (satış hattı, kişiler, etkileşimler) const CRMIcons = window.Icons; const CRM_STAGE_LIST = window.PMStore.CRM_STAGES; const CRM_ACT_LIST = window.PMStore.CRM_ACTIVITY_TYPES; const STAGE_BY_ID = Object.fromEntries(CRM_STAGE_LIST.map(s => [s.id, s])); const ACT_BY_ID = Object.fromEntries(CRM_ACT_LIST.map(a => [a.id, a])); const PIPELINE_STAGES = CRM_STAGE_LIST.filter(s => s.id !== 'won' && s.id !== 'lost'); const crmMoney = (n) => new Intl.NumberFormat('tr-TR', { maximumFractionDigits: 0 }).format(n || 0) + ' ₺'; const crmMoneyShort = (n) => Math.abs(n) >= 1000 ? new Intl.NumberFormat('tr-TR', { maximumFractionDigits: 1 }).format(n / 1000) + 'B ₺' : crmMoney(n); const crmInitials = (name) => (name || '?').split(/\s+/).filter(Boolean).map(w => w[0]).join('').slice(0, 2).toUpperCase(); const crmDateLabel = (d) => d ? new Date(d + 'T00:00:00').toLocaleDateString('tr-TR', { day: 'numeric', month: 'short' }) : ''; const onlyDigits = (s) => (s || '').replace(/[^\d+]/g, ''); // ── Fırsat kartı (satış hattı) ─────────────────────────────── function DealCard({ deal, firm, contact, onClick, onStageChange, onDragStart }) { const overdue = deal.expectedClose && deal.status === 'open' && new Date(deal.expectedClose + 'T00:00:00') < new Date(new Date().toDateString()); return (
{deal.title} {deal.value > 0 && {crmMoneyShort(deal.value)}}
{firm ? {firm.name} : deal.company && {deal.company}}
{(contact || deal.expectedClose) && (
{contact && {contact.name}} {deal.expectedClose && ( {crmDateLabel(deal.expectedClose)} )}
)}
); } // ── Kişi kartı ─────────────────────────────────────────────── function ContactCard({ contact, firm, onClick, dealCount }) { const color = firm?.color || 'var(--accent)'; return ( ); } // ── Yeni / Düzenle: Fırsat modalı ──────────────────────────── function DealModal({ state, editing, onSave, onDelete, onClose, onConvert }) { const isEdit = !!(editing && editing.id); const projects = (state.projects || []).filter(p => !p.archived); const [title, setTitle] = React.useState(editing?.title || ''); const [projectId, setProjectId] = React.useState(editing?.projectId || ''); const [company, setCompany] = React.useState(editing?.company || ''); const [contactId, setContactId] = React.useState(editing?.contactId || ''); const [value, setValue] = React.useState(editing?.value ? String(editing.value) : ''); const [stage, setStage] = React.useState(editing?.stage || 'lead'); const [expClose, setExpClose] = React.useState(editing?.expectedClose || ''); const [notes, setNotes] = React.useState(editing?.notes || ''); const firmContacts = (state.crmContacts || []).filter(c => projectId ? c.projectId === projectId : true); React.useEffect(() => { const fn = e => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', fn); return () => window.removeEventListener('keydown', fn); }, [onClose]); const save = () => { if (!title.trim()) return; onSave({ title: title.trim(), projectId: projectId || null, company: projectId ? '' : company.trim(), contactId: contactId || null, value: parseFloat(String(value).replace(',', '.')) || 0, stage, expectedClose: expClose || null, notes: notes.trim(), }); }; return (
e.stopPropagation()}>

{isEdit ? 'Fırsatı Düzenle' : 'Yeni Fırsat'}

{!projectId && ( )}
{firmContacts.length > 0 && ( )}