// ═══════════════════════════════════════════════════════════════ // RoutingTab.jsx — AI Akıllı Yönlendirme // Gelen çağrıları müşteri geçmişine göre AI ile yönlendirin // ═══════════════════════════════════════════════════════════════ const { useState, useEffect, useCallback } = React; // ── Koşul Şablonları ───────────────────────────────────────── const CONDITION_TEMPLATES = [ { key: 'customer_identified', label: 'Müşteri tanınıyor', type: 'bool' }, { key: 'tags_include_any', label: 'Etiket içerir (herhangi biri)', type: 'tags' }, { key: 'tags_include_all', label: 'Etiket içerir (hepsi)', type: 'tags' }, { key: 'tags_exclude', label: 'Etiket içermez', type: 'tags' }, { key: 'call_count_min', label: 'Min. çağrı sayısı', type: 'number' }, { key: 'call_count_max', label: 'Max. çağrı sayısı', type: 'number' }, { key: 'last_disposition_in', label: 'Son çağrı sonucu', type: 'tags' }, { key: 'is_blacklist', label: 'Kara listede', type: 'bool' }, { key: 'time_range', label: 'Saat aralığı', type: 'time_range' }, { key: 'weekdays', label: 'Hafta günleri', type: 'weekdays' }, ]; const ACTION_TYPES = [ { value: 'route_queue', label: 'Kuyruğa Yönlendir', icon: '' }, { value: 'route_ai_agent', label: 'AI Agent\'a Yönlendir', icon: '' }, { value: 'route_ivr', label: 'IVR Menüye Yönlendir', icon: '' }, { value: 'set_priority', label: 'Öncelik Ayarla', icon: '⬆' }, { value: 'reject', label: 'Çağrıyı Reddet', icon: '' }, { value: 'continue', label: 'Varsayılan Devam', icon: '▶' }, ]; const WEEKDAY_NAMES = ['Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt', 'Paz']; // ═══════════════════════════════════════════════════════════════ // Koşul Editörü // ═══════════════════════════════════════════════════════════════ function ConditionEditor({ conditions, onChange }) { const conds = conditions || {}; const setValue = (key, val) => { const next = { ...conds, [key]: val }; if (val === null || val === undefined || val === '' || (Array.isArray(val) && val.length === 0)) { delete next[key]; } onChange(next); }; const addCondition = (key) => { const tpl = CONDITION_TEMPLATES.find(t =>t.key === key); if (!tpl) return; const defaults = { bool: true, tags: [], number: 1, time_range: { start: '09:00', end: '18:00' }, weekdays: [1,2,3,4,5] }; setValue(key, defaults[tpl.type]); }; const removeCondition = (key) => { const next = { ...conds }; delete next[key]; onChange(next); }; const activeKeys = Object.keys(conds); const availableKeys = CONDITION_TEMPLATES.filter(t => !activeKeys.includes(t.key)); return (
{activeKeys.map(key => { const tpl = CONDITION_TEMPLATES.find(t =>t.key === key); if (!tpl) return null; return (
{tpl.label}
{tpl.type === 'bool' && ( )} {tpl.type === 'number' && ( setValue(key, parseInt(e.target.value) || 0)} /> )} {tpl.type === 'tags' && ( setValue(key, e.target.value.split(',').map(s =>s.trim()).filter(Boolean))} /> )} {tpl.type === 'time_range' && (
setValue(key, { ...conds[key], start: e.target.value })} /> setValue(key, { ...conds[key], end: e.target.value })} />
)} {tpl.type === 'weekdays' && (
{WEEKDAY_NAMES.map((name, i) => { const day = i + 1; const active = (conds[key] || []).includes(day); return ( ); })}
)}
); })} {availableKeys.length > 0 && ( )}
); } // ═══════════════════════════════════════════════════════════════ // Kural Düzenleme Modalı // ═══════════════════════════════════════════════════════════════ function RuleModal({ rule, targets, onClose, onSave }) { const empty = { name: '', description: '', priority: 10, is_active: true, conditions: {}, action_type: 'route_queue', target_id: null, priority_boost: 1, welcome_override: '', ai_hint: '' }; const [form, setForm] = useState(rule ? { ...empty, ...rule } : empty); const [saving, setSaving] = useState(false); const set = (k, v) =>setForm(f => ({ ...f, [k]: v })); const handleSave = async () => { if (!form.name) { alert('Kural adını girin'); return; } setSaving(true); onSave(form); setSaving(false); }; const targetOptions = () => { switch (form.action_type) { case 'route_queue': return (targets.queues || []).map(q => ({ id: q.id, label: `${q.name} (${q.extension})` })); case 'route_ai_agent': return (targets.ai_agents || []).map(a => ({ id: a.id, label: `${a.name} (${a.department || '-'})` })); case 'route_ivr': return (targets.ivr_menus || []).map(m => ({ id: m.id, label: m.name })); default: return []; } }; const needsTarget = ['route_queue', 'route_ai_agent', 'route_ivr'].includes(form.action_type); return (
e.stopPropagation()} style={{ maxWidth: 700 }}>
{rule ? 'Kuralı Düzenle' : 'Yeni Kural'}
{/* Temel Bilgiler */}
set('name', e.target.value)} placeholder="VIP Öncelikli Yönlendirme" />
set('priority', parseInt(e.target.value) || 0)} />
set('description', e.target.value)} placeholder="Bu kural ne zaman uygulanır?" />
{/* Koşullar */}
Koşullar

AI bu koşulları müşteri verisiyle karşılaştırarak kararını verir. Boş bırakılırsa kural her zaman geçerlidir.

set('conditions', v)} />
{/* Aksiyon */}
Aksiyon
{needsTarget && (
)}
{/* Özelleştirme */}
Özelleştirme
set('welcome_override', e.target.value)} placeholder="Değerli VIP müşterimiz, sizi öncelikli hatta yönlendiriyoruz." />