3import { useState, useEffect } from 'react';
4import { Icon } from '@/contexts/IconContext';
6interface DuplicateMatch {
21export default function DuplicateCustomersReport() {
22 const [duplicates, setDuplicates] = useState<DuplicateMatch[]>([]);
23 const [loading, setLoading] = useState(true);
24 const [error, setError] = useState<string | null>(null);
25 const [totalCustomers, setTotalCustomers] = useState(0);
31 const fetchDuplicates = async () => {
36 const response = await fetch('/api/v1/elink/advisor/duplicate-customers');
37 const data = await response.json();
40 throw new Error(data.error || 'Failed to fetch duplicates');
43 setDuplicates(data.duplicates || []);
44 setTotalCustomers(data.totalCustomers || 0);
46 console.error('Error fetching duplicates:', err);
47 setError(err.message);
55 <div className="p-6 min-h-screen bg-bg">
56 <div className="mb-6">
57 <div className="flex items-center gap-3 mb-2">
58 <a href="/pages/reports?source=advisor" className="text-muted hover:text-brand">
59 <Icon name="arrow_back" size={24} />
61 <h1 className="text-3xl font-bold text-text">Possible Duplicate Customers</h1>
63 <p className="text-muted ml-9">
64 Review potential duplicate customer records that may need to be merged
67 <div className="flex items-center justify-center py-12">
68 <div className="text-center">
69 <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-brand mx-auto mb-4"></div>
70 <p className="text-muted">Analyzing customer records...</p>
79 <div className="p-6 min-h-screen bg-bg">
80 <div className="mb-6">
81 <div className="flex items-center gap-3 mb-2">
82 <a href="/pages/reports?source=advisor" className="text-muted hover:text-brand">
83 <Icon name="arrow_back" size={24} />
85 <h1 className="text-3xl font-bold text-text">Possible Duplicate Customers</h1>
88 <div className="bg-surface rounded-lg shadow-sm border border-border p-6">
89 <div className="flex items-center gap-3 text-error mb-4">
90 <Icon name="error" size={24} />
91 <span className="font-medium">Error loading duplicates</span>
93 <p className="text-muted mb-4">{error}</p>
95 onClick={fetchDuplicates}
96 className="px-4 py-2 bg-brand text-white rounded hover:bg-brand2"
106 <div className="p-6 min-h-screen bg-bg">
107 <div className="mb-6">
108 <div className="flex items-center gap-3 mb-2">
109 <a href="/pages/reports?source=advisor" className="text-muted hover:text-brand">
110 <Icon name="arrow_back" size={24} />
112 <h1 className="text-3xl font-bold text-text">Possible Duplicate Customers</h1>
114 <p className="text-muted ml-9">
115 Review potential duplicate customer records that may need to be merged
117 {totalCustomers > 0 && (
118 <p className="text-muted text-sm ml-9 mt-1">
119 Analyzed {totalCustomers} customers • Found {duplicates.length} potential duplicate{duplicates.length !== 1 ? 's' : ''}
124 <div className="bg-surface rounded-lg shadow-sm border border-border overflow-hidden">
125 <div className="overflow-x-auto">
126 <table className="w-full">
127 <thead className="bg-[var(--brand)] text-surface">
129 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
132 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
135 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
138 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
141 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
144 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
149 <tbody className="divide-y divide-border">
150 {duplicates.length === 0 ? (
152 <td colSpan={6} className="px-6 py-12 text-center">
153 <Icon name="check_circle" size={48} className="text-success mx-auto mb-3" />
154 <p className="text-muted">No duplicate customers found</p>
155 <p className="text-muted text-sm mt-2">All customer records appear to be unique</p>
159 duplicates.map((dup, index) => (
160 <tr key={`${dup.id1}-${dup.id2}`} className="hover:bg-surface-2">
161 <td className="px-6 py-4 text-sm">
162 <div className="text-text font-medium">{dup.name1}</div>
163 <div className="text-muted text-xs">ID: {dup.id1}</div>
165 <td className="px-6 py-4 text-sm">
166 <div className="text-text font-medium">{dup.name2}</div>
167 <div className="text-muted text-xs">ID: {dup.id2}</div>
169 <td className="px-6 py-4 text-sm text-muted">
171 <div className="flex items-center gap-1">
172 <Icon name="phone" size={14} />
173 <span>{dup.phone1}</span>
177 <div className="flex items-center gap-1 mt-1">
178 <Icon name="mail" size={14} />
179 <span className="truncate max-w-[200px]">{dup.email1}</span>
183 <td className="px-6 py-4 text-sm text-muted">
186 <td className="px-6 py-4 whitespace-nowrap">
187 <span className={`px-2 py-1 text-xs font-medium rounded ${
188 dup.similarity >= 95 ? 'bg-error/20 text-error' :
189 dup.similarity >= 85 ? 'bg-warning/20 text-warning' :
190 'bg-surface-2 text-muted'
195 <td className="px-6 py-4 whitespace-nowrap text-sm space-x-3">
197 href={`/pages/customers/${dup.id1}`}
198 className="text-brand hover:text-brand2"
203 href={`/pages/customers/${dup.id2}`}
204 className="text-brand hover:text-brand2"