```jsx
'use client';
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import {
Users,
Kanban,
CheckSquare,
DollarSign,
UploadCloud,
Search,
Bell,
Phone,
Mail,
ArrowLeft,
ArrowRight,
Trophy,
AlertCircle,
FileText,
CheckCircle2,
ChevronRight,
MoreHorizontal,
Send,
CreditCard,
Building2,
Wallet,
ArrowDownUp,
Banknote,
X
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
// --- Mock Data ---
const INITIAL_CONTACTS = [
{ id: '1', name: 'Mark Hanson', company: 'HVAC Solutions', role: 'Owner', location: 'Chicago, IL', phone: '+1 (312) 555-0182', email: 'm.hanson@hvacsolutions.com', value: 2400, badge: 'Hot lead', badgeColor: 'text-red-400', stage: 3, avatar: 'MH', avatarBg: 'bg-red-900/30', notes: 'Wants website + SEO. Budget ~$2,500. Follow up Friday with proposal.' },
{ id: '2', name: 'Sarah Reem', company: 'GreenBuild Ltd.', role: 'Director', location: 'Austin, TX', phone: '+1 (512) 555-0231', email: 's.reem@greenbuild.com', value: 2800, badge: 'Warm', badgeColor: 'text-yellow-400', stage: 1, avatar: 'SR', avatarBg: 'bg-yellow-900/30', notes: '' },
{ id: '3', name: 'Tom Parker', company: 'Westside Woodwork', role: 'Owner', location: 'Denver, CO', phone: '+1 (720) 555-0144', email: 'tom@westsidewood.com', value: 1200, badge: 'New', badgeColor: 'text-blue-400', stage: 0, avatar: 'TP', avatarBg: 'bg-blue-900/30', notes: '' },
{ id: '4', name: 'Ana Lima', company: 'Spa Luxe Group', role: 'Manager', location: 'Miami, FL', phone: '+1 (305) 555-0376', email: 'ana.lima@spaluxe.com', value: 4200, badge: 'Warm', badgeColor: 'text-yellow-400', stage: 1, avatar: 'AL', avatarBg: 'bg-green-900/30', notes: '' },
{ id: '5', name: 'David Kim', company: 'Metro Plumbing', role: 'Owner', location: 'Seattle, WA', phone: '+1 (206) 555-0289', email: 'd.kim@metroplumb.com', value: 3500, badge: 'New', badgeColor: 'text-blue-400', stage: 0, avatar: 'DK', avatarBg: 'bg-purple-900/30', notes: '' },
{ id: '6', name: 'Ben Walsh', company: 'Walsh Roofing', role: 'Owner', location: 'Portland, OR', phone: '+1 (503) 555-0412', email: 'ben@walshroofing.com', value: 1800, badge: 'Closed', badgeColor: 'text-emerald-400', stage: 5, avatar: 'BW', avatarBg: 'bg-orange-900/30', notes: '' },
];
const STAGES = ['New', 'Follow-up', 'Meeting', 'Quote sent', 'Negotiating', 'Closed'];
const DAILY_TASKS = [
{ id: 'calls', label: '8 cold calls', current: 3, target: 8 },
{ id: 'followups', label: '5 follow-up emails', current: 2, target: 5 },
{ id: 'quotes', label: '2 quotes sent', current: 0, target: 2 },
{ id: 'meetings', label: '1 meeting booked', current: 0, target: 1 },
{ id: 'pipeline', label: 'Pipeline updated', current: 0, target: 1 },
];
const REVENUE_DATA = [
{ id: 'r1', client: 'Ben Walsh โ Walsh Roofing', value: 1800, method: 'Stripe', status: 'Paid' },
{ id: 'r2', client: 'Jen Morris โ City Spa', value: 2400, method: 'Bank transfer', status: 'Paid' },
];
// --- Components ---
const ProgressBar = ({ value, max, color = 'bg-emerald-500' }) => (
);
const Avatar = ({ initials, bgColor, size = 'md', className = '' }) => {
const sizes = { sm: 'w-6 h-6 text-[10px]', md: 'w-9 h-9 text-xs', lg: 'w-10 h-10 text-sm' };
return (
{initials}
);
};
const Button = ({ children, variant = 'primary', size = 'md', icon: Icon, className = '', onClick, disabled }) => {
const variants = {
primary: 'bg-[#4A90E2] hover:bg-[#3B7DD0] text-white',
secondary: 'bg-gray-700/40 hover:bg-gray-700/60 text-gray-200 border border-gray-700/50',
success: 'bg-emerald-600 hover:bg-emerald-500 text-white',
danger: 'bg-red-600 hover:bg-red-500 text-white',
ghost: 'bg-transparent hover:bg-gray-700/30 text-gray-300',
};
const sizes = {
sm: 'px-2.5 py-1.5 text-xs',
md: 'px-3 py-2 text-xs',
lg: 'px-4 py-2.5 text-sm',
};
return (
);
};
const Modal = ({ isOpen, onClose, title, children }) => {
if (!isOpen) return null;
return (
);
};
// --- Main Application ---
export default function SalesRepCRM() {
const [activeTab, setActiveTab] = useState('contact');
const [contacts, setContacts] = useState(INITIAL_CONTACTS);
const [selectedContactId, setSelectedContactId] = useState(INITIAL_CONTACTS[0].id);
const [wins, setWins] = useState(2);
const [tasks, setTasks] = useState(DAILY_TASKS.map(t => ({ ...t, done: false })));
const [isInvoiceOpen, setIsInvoiceOpen] = useState(false);
const [notification, setNotification] = useState(null);
const [importPhase, setImportPhase] = useState('idle'); // idle, mapping, done
const selectedContact = contacts.find(c => c.id === selectedContactId) || contacts[0];
const showNotify = useCallback((msg, type = 'success') => {
setNotification({ msg, type });
setTimeout(() => setNotification(null), 3000);
}, []);
const updateStage = useCallback((id, newStage) => {
setContacts(prev => prev.map(c => c.id === id ? { ...c, stage: newStage, badge: newStage === 5 ? 'Closed' : c.badge, badgeColor: newStage === 5 ? 'text-emerald-400' : c.badgeColor } : c));
}, []);
const handleMove = useCallback((dir) => {
const currentStage = selectedContact.stage;
const nextStage = dir === 'fwd' ? Math.min(5, currentStage + 1) : Math.max(0, currentStage - 1);
if (nextStage !== currentStage) {
updateStage(selectedContact.id, nextStage);
showNotify(`Moved ${selectedContact.name} to ${STAGES[nextStage]}`);
if (nextStage === 5) {
setWins(w => w + 1);
showNotify(`๐ Deal closed for ${selectedContact.name}!`);
}
}
}, [selectedContact, updateStage, showNotify]);
const toggleTask = useCallback((id) => {
setTasks(prev => {
const updated = prev.map(t => t.id === id ? { ...t, done: !t.done } : t);
const doneCount = updated.filter(t => t.done).length;
setWins(doneCount); // Sync wins with tasks for this demo
return updated;
});
}, []);
const handleImport = useCallback(() => {
if (importPhase === 'idle') {
setImportPhase('mapping');
showNotify('File loaded. 47 contacts detected. Please map columns.');
} else {
setImportPhase('done');
showNotify('โ
47 contacts successfully imported.');
setTimeout(() => setImportPhase('idle'), 2000);
}
}, [importPhase, showNotify]);
// --- Views ---
const ContactView = () => {
const c = selectedContact;
return (
{/* Header */}
{c.name}
{c.badge}
{c.role} ยท {c.company} ยท {c.location}
{/* Stage Indicator */}
{STAGES.map((stage, idx) => {
const isPast = idx < c.stage;
const isCurrent = idx === c.stage;
return (
{idx < 5 && }
);
})}
{/* Actions */}
{/* Content Grid */}
{/* Notes */}
Call Notes
{['Draft email', 'Objections', 'Meeting email'].map(action => (
))}
{/* Activity */}
Activity History
{[
{ type: 'Quote sent', detail: '$2,400 website package', time: '2 days ago', color: 'bg-yellow-400/80' },
{ type: 'Meeting', detail: 'Discussed design & scope', time: '4 days ago', color: 'bg-[#4A90E2]' },
{ type: 'Call', detail: '14 min, showed interest', time: '7 days ago', color: 'bg-[#4A90E2]' },
{ type: 'Imported', detail: 'From CSV file', time: '10 days ago', color: 'bg-gray-500' }
].map((item, i) => (
{item.type}
โ {item.detail}
{item.time}
))}
);
};
const PipelineView = () => {
return (
Sales Pipeline
Total Value: $18,650
{STAGES.map((stage, idx) => {
const stageContacts = contacts.filter(c => c.stage === idx);
return (
{stage}
{stageContacts.length}
{stageContacts.map(c => (
{ setSelectedContactId(c.id); setActiveTab('contact'); }}
className="bg-[#212121] border border-gray-700/30 p-3 rounded-lg cursor-pointer hover:border-gray-600 hover:bg-[#25262C] transition-all group"
>
${c.value.toLocaleString()}
))}
);
})}
);
};
const AccountabilityView = () => {
const tasksDone = tasks.filter(t => t.done).length;
return (
{[
{ label: 'Calls made', value: '3', sub: 'Target: 8 today' },
{ label: 'Follow-ups sent', value: '2', sub: 'Target: 5 today' },
{ label: 'Deals moved', value: '1', sub: 'This week: 4' },
{ label: 'Revenue logged', value: '$1,800', sub: 'This month' }
].map((stat, i) => (
{stat.label}
{stat.value}
{stat.sub}
))}
Daily Targets
{tasksDone} / 5 done
{tasks.map(task => (
toggleTask(task.id)}>
{task.done && }
{task.label}
{task.current} / {task.target}
))}
Monthly Quota
42% to goal
{[
{ label: 'Revenue closed', val: '$4,200', pct: 42, color: 'bg-emerald-500' },
{ label: 'Calls made', val: '61%', pct: 61, color: 'bg-[#4A90E2]' },
{ label: 'Deals in pipe', val: '$16.8k', pct: 78, color: 'bg-yellow-500/80' },
{ label: 'Win rate', val: '67%', pct: 67, color: 'bg-purple-500/80' }
].map((prog, i) => (
))}
);
};
const RevenueView = () => (
Closed this month$4,200
2 deals
Pipeline value$16,850
7 active
Avg deal size$2,100
vs $1,800 prior
Closed Deals
| Client |
Value |
Payment |
Status |
Performance |
{REVENUE_DATA.map(row => (
| {row.client} |
${row.value.toLocaleString()} |
{row.method} |
Paid |
|
))}
);
const ImportView = () => (
Import Leads
{importPhase === 'idle' && (
Drop your file here or click to upload
Name, company, phone, email, industry โ auto-detected
{['.csv', '.xlsx', '.xls'].map(ext => (
{ext}
))}
)}
{importPhase === 'mapping' && (
Map columns โ 47 contacts detected
{[
{ col: 'Column A: "Full Name"', to: 'Contact name' },
{ col: 'Column B: "Business"', to: 'Company name' },
{ col: 'Column C: "Phone"', to: 'Phone' },
{ col: 'Column D: "Email"', to: 'Email' },
{ col: 'Column E: "Industry"', to: 'Industry tag' },
].map((row, i) => (
{row.col}
))}
)}
{importPhase === 'done' && (
Import Successful
47 new contacts have been added to your pipeline.
)}
);
return (
{/* Sidebar */}
{/* Main Layout */}
{/* Topbar */}
{/* Content Area */}
{activeTab === 'contact' &&
}
{activeTab === 'pipeline' &&
}
{activeTab === 'accountability' &&
}
{activeTab === 'revenue' &&
}
{activeTab === 'import' &&
}
{/* Invoice Modal */}
setIsInvoiceOpen(false)} title={`Invoice for ${selectedContact.name}`}>
Auto-filled from profile. Add line items, select payment method, send.
{[
{ item: 'Website design', price: 1800 },
{ item: 'SEO setup (3 months)', price: 600 }
].map((row, i) => (
{row.item}
${row.price.toLocaleString()}
))}
Total
$2,400
Send payment via
{[
{ id: 'stripe', label: 'Stripe', icon: CreditCard },
{ id: 'bank', label: 'Bank transfer', icon: Building2 },
{ id: 'paypal', label: 'PayPal', icon: Wallet },
{ id: 'wise', label: 'Wise', icon: ArrowDownUp },
{ id: 'cash', label: 'Cash / Other', icon: Banknote },
{ id: 'payoneer', label: 'Payoneer', icon: GlobeIcon },
].map(pm => (
))}
{/* Global Notification */}
{notification && (
{notification.type === 'success' ? : }
{notification.msg}
)}
);
}
// Simple icon replacement for the grid
const GlobeIcon = ({size, className}) => (
);
```