feat: add documents, goals, and referrals UI

- ClientDocuments tab with drag-and-drop upload, category filter, download/delete
- ClientGoals tab with progress bars, status badges, add/edit/complete
- ClientReferrals tab with given/received views, client search, status management
- Dashboard widgets: goals overview and referral leaderboard
- API client methods for all new endpoints
This commit is contained in:
2026-01-30 04:41:29 +00:00
parent b0cfa0ab1b
commit f042c910ee
6 changed files with 1060 additions and 3 deletions

View File

@@ -7,6 +7,7 @@ import {
ArrowLeft, Edit3, Trash2, Phone, Mail, MapPin, Building2,
Briefcase, Gift, Heart, Star, Users, Calendar, Send,
CheckCircle2, Sparkles, Clock, Activity, FileText, UserPlus, RefreshCw,
Paperclip, Target,
} from 'lucide-react';
import { usePinnedClients } from '@/hooks/usePinnedClients';
import { cn, formatDate, getRelativeTime, getInitials } from '@/lib/utils';
@@ -20,6 +21,9 @@ import LogInteractionModal from '@/components/LogInteractionModal';
import MeetingPrepModal from '@/components/MeetingPrepModal';
import EngagementBadge from '@/components/EngagementBadge';
import DuplicatesModal from '@/components/DuplicatesModal';
import ClientDocuments from '@/components/ClientDocuments';
import ClientGoals from '@/components/ClientGoals';
import ClientReferrals from '@/components/ClientReferrals';
import type { Interaction } from '@/types';
export default function ClientDetailPage() {
@@ -29,7 +33,7 @@ export default function ClientDetailPage() {
const [events, setEvents] = useState<Event[]>([]);
const [emails, setEmails] = useState<Email[]>([]);
const [activities, setActivities] = useState<ActivityItem[]>([]);
const [activeTab, setActiveTab] = useState<'info' | 'notes' | 'activity' | 'events' | 'emails'>('info');
const [activeTab, setActiveTab] = useState<'info' | 'notes' | 'activity' | 'events' | 'emails' | 'documents' | 'goals' | 'referrals'>('info');
const [, setInteractions] = useState<Interaction[]>([]);
const [showEdit, setShowEdit] = useState(false);
const [showCompose, setShowCompose] = useState(false);
@@ -76,6 +80,9 @@ export default function ClientDetailPage() {
const tabs: { key: typeof activeTab; label: string; count?: number; icon: typeof Users }[] = [
{ key: 'info', label: 'Info', icon: Users },
{ key: 'notes', label: 'Notes', icon: FileText },
{ key: 'documents', label: 'Documents', icon: Paperclip },
{ key: 'goals', label: 'Goals', icon: Target },
{ key: 'referrals', label: 'Referrals', icon: UserPlus },
{ key: 'activity', label: 'Timeline', count: activities.length, icon: Activity },
{ key: 'events', label: 'Events', count: events.length, icon: Calendar },
{ key: 'emails', label: 'Emails', count: emails.length, icon: Mail },
@@ -277,6 +284,18 @@ export default function ClientDetailPage() {
<ClientNotes clientId={client.id} />
)}
{activeTab === 'documents' && (
<ClientDocuments clientId={client.id} />
)}
{activeTab === 'goals' && (
<ClientGoals clientId={client.id} />
)}
{activeTab === 'referrals' && (
<ClientReferrals clientId={client.id} clientName={`${client.firstName} ${client.lastName}`} />
)}
{activeTab === 'activity' && (
<div className="bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-xl">
{activities.length === 0 ? (