/* AAU CRM — Customer Profile 360 — playbook-aware (script, qualify gate, signals, MAKE THE MOVE) */ function StatCard({ icon, label, value, tone }) { return (
{label}
{value}
); } function CustomerProfile360({ id }) { const leads = useLeads(); const viewer = useViewer(); const lead = LeadStore.byId(id); const [tab, setTab] = useState('overview'); const [move, setMove] = useState(false); const [assign, setAssign] = useState(false); const [edit, setEdit] = useState(false); if (!lead) return
navigate('/leads')}>Về danh sách} />
; if (!SalesAccess.canSee(lead, viewer)) return
navigate('/leads')}>Về Pipeline} />
; const canEdit = SalesAccess.canEdit(viewer); const st = AAU.stageById(lead.stage); const g = pbGuide(st.code) || {}; const meta = (window.PLAYBOOK && PLAYBOOK.scriptTypeMeta[g.type]) || {}; const qCount = Object.values(lead.qualify).filter(Boolean).length; const seedTimeline = [ { type: 'chat', icon: 'message', color: '#0084ff', at: '8 phút trước', title: 'Tin nhắn ' + (AAU.channels[lead.channel]?.label || ''), sub: lead.signal ? '"' + lead.signal.text + '"' : 'Khách tương tác' }, { type: 'asset', icon: 'paperclip', color: '#573b8a', at: '2 giờ trước', title: 'Đã gửi tài liệu', sub: (g.send && g.send[0]) || 'Brochure' }, { type: 'create', icon: 'plus', color: '#8a8a8a', at: AAU.fmtDate(lead.createdAt), title: 'Lead được tạo', sub: 'Nguồn: ' + (AAU.sourceMeta[lead.source]?.label) + ' · Nhánh ' + (lead.branch || '—') }, ]; const moveHist = (lead.history || []).map(h => ({ type: 'stage', icon: 'kanban', color: '#f59e0b', at: h.at, title: 'Chuyển ' + h.from + ' → ' + h.to, sub: 'Lý do: ' + h.reason + ' · trigger: ' + h.trigger })); const timeline = [...moveHist, ...seedTimeline]; const qLabels = { bizModel: ['Mô hình kinh doanh rõ', lead.bizModel + ' · ' + lead.chainSize], painpoint: ['Có painpoint cụ thể', lead.painpoints[0] || '—'], courseMap: ['Map đúng khóa học', AAU.courseById(lead.courseInterest)?.name || '—'], budget: ['Đủ khả năng tài chính', 'Doanh thu ~' + AAU.fmtVNDm(lead.revenue) + '/th'] }; return (
navigate('/leads') }, { label: lead.company }]} title={{lead.company} {lead.hot && }} subtitle={lead.name + ' · ' + lead.role + ' · ' + lead.bizModel + ' · ' + lead.region} actions={<>{canEdit && }{canEdit ? : }} />
{st.branch && } {st.lane && } {lead.signal && } {lead.dealValue > 0 && Deal {AAU.fmtVND(lead.dealValue)}} Khóa: {(AAU.courseById(lead.courseInterest) || {}).code || '—'} Phụ trách: {AAU.users.find(u => u.id === lead.assignedTo)?.name || 'Chưa gán'}{canEdit && setAssign(true)}>{lead.assignedTo ? 'Đổi' : 'Phân công'}}
= 4 ? '#0e7c4a' : '#b06f00'} />
{tab === 'overview' && (
ĐỊNH DANH
{lead.fb}} />
KINH DOANH (B2B)
NHU CẦU
{lead.painpoints.map((p, i) => {p})}{AAU.courseById(lead.courseInterest)?.name}
ATTRIBUTION & DEAL
{lead.objection &&
OBJECTION / BLOCKER
{lead.objection}
}
)} {tab === 'qualify' && (
Lead phải đủ 4 điều kiện mới được move sang 3.1 Qualify. Click để cập nhật.
{Object.keys(qLabels).map(k => { const on = !!lead.qualify[k]; return (
LeadStore.toggleQualify(lead.id, k) : undefined}>
{qLabels[k][0]}
{qLabels[k][1]}
); })}
Qualify score: {qCount}/4 — {qCount >= 4 ? Đủ điều kiện → 3.1 Qualify : Thiếu {4 - qCount} điều kiện → nurture 3.0 (SOFT)}
)} {tab === 'timeline' && (
{timeline.map((t, i) => (
{i < timeline.length - 1 &&
}
{t.title}{t.at}
{t.sub}
))}
)} {tab === 'history' && ( (lead.history && lead.history.length) ? ( {lead.history.map((h, i) => )}
TừĐếnLý doTrigger
{h.from}{h.to}{h.reason}{h.trigger}
) : )}
{/* MAKE THE MOVE script card */}
{st.code} · {g.title || st.name}
{g.objective}
{g.openings && g.openings.length > 0 && (
KỊCH BẢN — {meta.label}
{g.openings.map((o, i) =>
{o}
)}
)} {g.send && g.send.length > 0 && (
Tài liệu gửi
{g.send.map((s, i) => {s})}
)} {g.cadence &&
{g.cadence}
} {canEdit ? :
Vai trò chỉ-xem — không thể chuyển stage.
}
{/* next action */}
Hành động kế tiếp
{lead.nextAction}
{move && setMove(false)} onMove={(lid, to, r, t) => { LeadStore.move(lid, to, r, t); setMove(false); }} onToggleQualify={(lid, k) => LeadStore.toggleQualify(lid, k)} readOnly={!canEdit} />} {assign && setAssign(false)} />} {edit && setEdit(false)} />}
); } function LeadEditDrawer({ lead, onClose }) { const [f, setF] = useState({ phone: lead.phone, email: lead.email, fb: lead.fb, region: lead.region, bizModel: lead.bizModel, industry: lead.industry, chainSize: lead.chainSize, revenue: lead.revenue, dealValue: lead.dealValue || 0, painpoints: (lead.painpoints || []).join(', '), objection: lead.objection || '', }); const set = (k, v) => setF(p => ({ ...p, [k]: v })); const num = v => Number(String(v).replace(/\D/g, '')) || 0; function save() { LeadStore.update(lead.id, { phone: f.phone, email: f.email, fb: f.fb, region: f.region, bizModel: f.bizModel, industry: f.industry, chainSize: f.chainSize, revenue: num(f.revenue), dealValue: num(f.dealValue), painpoints: f.painpoints.split(',').map(s => s.trim()).filter(Boolean), objection: f.objection.trim(), }); onClose(); } return ( }>
Thông tin định danh & B2B do sales nhập tay (chat tự động chỉ gợi ý). Qualify chỉnh ở tab Qualify.
ĐỊNH DANH
set('phone', v)} /> set('email', v)} /> set('fb', v)} /> set('region', v)} />
KINH DOANH (B2B)
set('bizModel', v)} /> set('industry', v)} /> set('chainSize', v)} /> set('revenue', v)} />
NHU CẦU & DEAL
set('painpoints', v)} placeholder="Chi phí cao, Chưa chuẩn SOP" />
set('dealValue', v)} /> set('objection', v)} placeholder="vd Cần thuyết phục đồng sáng lập" />
); } Object.assign(window, { CustomerProfile360, StatCard });