import { SlideoutMenu } from '@/components/application/slideout-menus/slideout-menu'; import { formatPhone, formatShortDate } from '@/lib/format'; import type { Lead, LeadActivity, LeadActivityType } from '@/types/entities'; import { cx } from '@/utils/cx'; type LeadActivitySlideoutProps = { isOpen: boolean; onOpenChange: (open: boolean) => void; lead: Lead; activities: LeadActivity[]; }; type ActivityConfig = { icon: string; dotClass: string; label: string; }; const ACTIVITY_CONFIG: Record = { STATUS_CHANGE: { icon: '๐Ÿ”„', dotClass: 'bg-brand-secondary', label: 'Status Changed' }, CALL_MADE: { icon: '๐Ÿ“ž', dotClass: 'bg-brand-secondary', label: 'Call Made' }, CALL_RECEIVED: { icon: '๐Ÿ“ฒ', dotClass: 'bg-brand-secondary', label: 'Call Received' }, WHATSAPP_SENT: { icon: '๐Ÿ’ฌ', dotClass: 'bg-success-solid', label: 'WhatsApp Sent' }, WHATSAPP_RECEIVED: { icon: '๐Ÿ’ฌ', dotClass: 'bg-success-solid', label: 'WhatsApp Received' }, SMS_SENT: { icon: 'โœ‰๏ธ', dotClass: 'bg-brand-secondary', label: 'SMS Sent' }, EMAIL_SENT: { icon: '๐Ÿ“ง', dotClass: 'bg-brand-secondary', label: 'Email Sent' }, EMAIL_RECEIVED: { icon: '๐Ÿ“ง', dotClass: 'bg-brand-secondary', label: 'Email Received' }, NOTE_ADDED: { icon: '๐Ÿ“', dotClass: 'bg-warning-solid', label: 'Note Added' }, ASSIGNED: { icon: '๐Ÿ“ค', dotClass: 'bg-brand-secondary', label: 'Assigned' }, APPOINTMENT_BOOKED: { icon: '๐Ÿ“…', dotClass: 'bg-brand-secondary', label: 'Appointment Booked' }, FOLLOW_UP_CREATED: { icon: '๐Ÿ”', dotClass: 'bg-brand-secondary', label: 'Follow-up Created' }, CONVERTED: { icon: 'โœ…', dotClass: 'bg-success-solid', label: 'Converted' }, MARKED_SPAM: { icon: '๐Ÿšซ', dotClass: 'bg-error-solid', label: 'Marked as Spam' }, DUPLICATE_DETECTED: { icon: '๐Ÿ”', dotClass: 'bg-warning-solid', label: 'Duplicate Detected' }, }; const DEFAULT_CONFIG: ActivityConfig = { icon: '๐Ÿ“Œ', dotClass: 'bg-tertiary', label: 'Activity' }; const StatusChangeContent = ({ previousValue, newValue }: { previousValue: string | null; newValue: string | null }) => ( {previousValue && ( {previousValue} )} {previousValue && newValue && 'โ†’ '} {newValue && {newValue}} ); const ActivityItem = ({ activity, isLast }: { activity: LeadActivity; isLast: boolean }) => { const type = activity.activityType; const config = type ? (ACTIVITY_CONFIG[type] ?? DEFAULT_CONFIG) : DEFAULT_CONFIG; const occurredAt = activity.occurredAt ? formatShortDate(activity.occurredAt) : ''; return (
{/* Vertical connecting line */} {!isLast && (
)} {/* Dot */} {/* Content */}
{activity.summary ?? config.label}
{type === 'STATUS_CHANGE' && (activity.previousValue || activity.newValue) && ( )} {type !== 'STATUS_CHANGE' && activity.newValue && (

{activity.newValue}

)}

{occurredAt} {activity.performedBy ? ` ยท by ${activity.performedBy}` : ''}

); }; export const LeadActivitySlideout = ({ isOpen, onOpenChange, lead, activities }: LeadActivitySlideoutProps) => { const firstName = lead.contactName?.firstName ?? ''; const lastName = lead.contactName?.lastName ?? ''; const fullName = `${firstName} ${lastName}`.trim() || 'Unknown Lead'; const phone = lead.contactPhone?.[0] ? formatPhone(lead.contactPhone[0]) : null; const email = lead.contactEmail?.[0]?.address ?? null; const filteredActivities = activities .filter((a) => a.leadId === lead.id) .sort((a, b) => { if (!a.occurredAt) return 1; if (!b.occurredAt) return -1; return new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime(); }); return ( {({ close }) => ( <>

Lead Activity โ€” {fullName}

{[phone, email, lead.leadSource, lead.utmCampaign] .filter(Boolean) .join(' ยท ')}

{filteredActivities.length === 0 ? (
๐Ÿ“ญ

No activity yet

Activity will appear here as interactions occur.

) : (
{filteredActivities.map((activity, idx) => ( ))}
)}
)}
); };