PageSourceSearch

https://servicebro.io/assets/CustomerDuplicatesPage-BOnaf-Wt.js

js servicebro.io collected 2026-10-02 16:13:55 UTC 10,788 bytes, 6 lines download raw bytes

1import{$ as U,V,m as X,r as n,s as w,j as e,n as H,aj as J,y as O,X as P,I as y,x as F,L as Q,g as W,q as Y,M as Z}from"./index-CUROJguC.js";import{P as ee}from"./phone-BJinYZDP.js";/**
2 * @license lucide-react v0.344.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const se=U("Merge",[["path",{d:"m8 6 4-4 4 4",key:"ybng9g"}],["path",{d:"M12 2v10.3a4 4 0 0 1-1.172 2.872L4 22",key:"1hyw0i"}],["path",{d:"m20 22-5-5",key:"1m27yz"}]]);function re(){const{effectiveProviderId:o}=V(),A=X(),[v,G]=n.useState([]),[u,k]=n.useState(!0),[h,M]=n.useState([]),[b,R]=n.useState("all"),[q,C]=n.useState({}),[z,f]=n.useState(null),[S,p]=n.useState(null),[E,g]=n.useState(null),_=n.useMemo(()=>b==="all"?h:h.filter(s=>s.matchType===b),[h,b]),j=n.useCallback(async()=>{if(!o)return;k(!0),M([]),C({});const{data:s,error:i}=await w.from("customers").select("id, first_name, last_name, email, phone, address, city, company_name, created_at").eq("provider_id",o).order("created_at",{ascending:!0});i?p(i.message):s&&(G(s),L(s)),k(!1)},[o]);n.useEffect(()=>{o&&j()},[o,j]);function L(s){const i=[],l=new Set,r=new Map,d=new Map,t=new Map;s.forEach(a=>{var D,$;const c=(D=a.phone)==null?void 0:D.replace(/[\s().+-]/g,"").toLowerCase();if(c&&c.length>6){const x=r.get(c)||[];x.push(a),r.set(c,x)}const m=($=a.email)==null?void 0:$.toLowerCase().trim();if(m){const x=d.get(m)||[];x.push(a),d.set(m,x)}const N=`${a.first_name.trim().toLowerCase()} ${a.last_name.trim().toLowerCase()}`;if(N.length>3){const x=t.get(N)||[];x.push(a),t.set(N,x)}}),r.forEach(a=>{if(a.length>1){const c=a.map(m=>m.id).sort().join("-");l.has(c)||(l.add(c),i.push({matchType:"phone",customers:a}))}}),d.forEach(a=>{if(a.length>1){const c=a.map(m=>m.id).sort().join("-");l.has(c)||(l.add(c),i.push({matchType:"email",customers:a}))}}),t.forEach(a=>{if(a.length>1){const c=a.map(m=>m.id).sort().join("-");l.has(c)||(l.add(c),i.push({matchType:"name",customers:a}))}}),M(i)}async function I(s,i){if(!o)return;f(i+"-"+s.customers[0].id),p(null),g(null);const l=s.customers.filter(r=>r.id!==i).map(r=>r.id);if(l.length===0){f(null);return}try{const{error:r}=await w.rpc("merge_customers",{p_master_id:i,p_duplicate_ids:l,p_provider_id:o});if(r)throw r;const{data:d,error:t}=await w.from("customers").select("id").in("id",l).eq("provider_id",o);t?p("Merge completed, but verification failed: "+t.message):d&&d.length>0?p(`Merge reported success, but ${d.length} duplicate customer record(s) still exist. Refresh or contact support.`):g(`Merged ${l.length} duplicate(s) successfully`),await j()}catch(r){p(r instanceof Error?r.message:"Failed to merge duplicates")}finally{f(null)}}function B(){L(v),p(null),g(null)}const T=s=>{switch(s){case"phone":return"Same Phone";case"email":return"Same Email";case"name":return"Same Name";default:return s}},K=s=>{switch(s){case"phone":return"bg-red-100 text-red-700 border-red-200";case"email":return"bg-amber-100 text-amber-700 border-amber-200";case"name":return"bg-blue-100 text-blue-700 border-blue-200";default:return"bg-slate-100 text-slate-700 border-slate-200"}};return e.jsx("div",{className:"min-h-screen bg-stone-100 text-slate-900 -m-3 lg:-m-6 p-3 pb-24 sm:p-4 sm:pb-24 lg:p-8 lg:pb-8",children:e.jsxs("div",{className:"max-w-full mx-auto space-y-4 lg:space-y-6",children:[e.jsx("header",{className:"pt-2 sm:pt-4 pb-4 sm:pb-6 border-b-2 border-slate-900",children:e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-2",children:[e.jsx("button",{onClick:()=>A("/dashboard/customers"),className:"p-2 hover:bg-slate-100 transition-colors border-2 border-slate-200",children:e.jsx(H,{className:"w-4 h-4"})}),e.jsx("p",{className:"text-slate-500 uppercase tracking-[0.3em] text-[9px] sm:text-[10px]",children:new Date().toLocaleDateString("en-GB",{weekday:"short",day:"numeric",month:"short"})})]}),e.jsx("h1",{className:"text-2xl sm:text-4xl lg:text-5xl font-black tracking-tighter leading-none",children:"MERGE DUPLICATES"}),e.jsx("p",{className:"text-slate-500 text-sm mt-2",children:"Find and merge duplicate customer records"})]}),e.jsxs("button",{onClick:B,disabled:u,className:"flex-shrink-0 inline-flex items-center gap-2 border-2 border-slate-900 px-3 sm:px-4 py-2.5 sm:py-3 font-bold uppercase tracking-wider text-xs sm:text-sm hover:bg-slate-100 transition-colors disabled:opacity-50",children:[e.jsx(J,{className:`w-4 h-4 ${u?"animate-spin":""}`}),e.jsx("span",{className:"hidden sm:inline",children:"Rescan"})]})]})}),S&&e.jsxs("div",{className:"bg-red-50 border-2 border-red-200 p-4 flex items-start gap-3",children:[e.jsx(O,{className:"w-5 h-5 text-red-600 flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-bold text-red-900 text-sm",children:"Error"}),e.jsx("p",{className:"text-red-700 text-sm",children:S})]}),e.jsx("button",{onClick:()=>p(null),className:"text-red-600 hover:text-red-800",children:e.jsx(P,{className:"w-4 h-4"})})]}),E&&e.jsxs("div",{className:"bg-emerald-50 border-2 border-emerald-200 p-4 flex items-start gap-3",children:[e.jsx(y,{className:"w-5 h-5 text-emerald-600 flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-bold text-emerald-900 text-sm",children:"Success"}),e.jsx("p",{className:"text-emerald-700 text-sm",children:E})]}),e.jsx("button",{onClick:()=>g(null),className:"text-emerald-600 hover:text-emerald-800",children:e.jsx(P,{className:"w-4 h-4"})})]}),u?e.jsxs("div",{className:"bg-white border-2 border-slate-900 p-12 text-center",children:[e.jsx(F,{className:"w-8 h-8 animate-spin mx-auto mb-3 text-slate-400"}),e.jsx("p",{className:"text-sm text-slate-500",children:"Scanning for duplicates..."})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-2 sm:gap-3",children:[e.jsxs("div",{className:"bg-white border-2 border-slate-900 p-3 sm:p-4",children:[e.jsx("p",{className:"text-[8px] sm:text-[9px] uppercase tracking-[0.15em] text-slate-400 mb-1",children:"Total Customers"}),e.jsx("p",{className:"text-2xl sm:text-3xl font-black",children:v.length})]}),e.jsxs("div",{className:"bg-white border-2 border-slate-900 p-3 sm:p-4",children:[e.jsx("p",{className:"text-[8px] sm:text-[9px] uppercase tracking-[0.15em] text-slate-400 mb-1",children:"Duplicate Groups"}),e.jsx("p",{className:"text-2xl sm:text-3xl font-black",children:h.length})]}),e.jsxs("div",{className:"bg-red-50 border-2 border-red-200 p-3 sm:p-4",children:[e.jsx("p",{className:"text-[8px] sm:text-[9px] uppercase tracking-[0.15em] text-red-600 mb-1",children:"Phone Duplicates"}),e.jsx("p",{className:"text-2xl sm:text-3xl font-black text-red-700",children:h.filter(s=>s.matchType==="phone").length})]}),e.jsxs("div",{className:"bg-amber-50 border-2 border-amber-200 p-3 sm:p-4",children:[e.jsx("p",{className:"text-[8px] sm:text-[9px] uppercase tracking-[0.15em] text-amber-600 mb-1",children:"Email Duplicates"}),e.jsx("p",{className:"text-2xl sm:text-3xl font-black text-amber-700",children:h.filter(s=>s.matchType==="email").length})]})]}),e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:["all","email","name","phone"].map(s=>e.jsx("button",{onClick:()=>R(s),className:`px-3 py-2 text-[10px] sm:text-xs font-bold uppercase tracking-wider border-2 transition-colors ${b===s?"bg-slate-900 text-white border-slate-900":"bg-white text-slate-700 border-slate-200 hover:border-slate-900"}`,children:s==="all"?"All":T(s)},s))}),_.length===0?e.jsxs("div",{className:"bg-white border-2 border-slate-900 p-8 sm:p-12 text-center",children:[e.jsx(y,{className:"w-12 h-12 sm:w-16 sm:h-16 text-emerald-500 mx-auto mb-4"}),e.jsx("p",{className:"text-lg sm:text-xl font-black uppercase tracking-wider text-slate-900 mb-2",children:"No Duplicates Found"}),e.jsx("p",{className:"text-slate-500 text-sm mb-6",children:"All your customer records look unique"}),e.jsx(Q,{to:"/dashboard/customers",className:"inline-flex items-center gap-2 bg-slate-900 text-white px-5 py-3 font-bold uppercase tracking-wider text-sm hover:bg-slate-800 transition-colors",children:"Back to Customers"})]}):e.jsx("div",{className:"space-y-4",children:_.map((s,i)=>{const l=s.customers.map(t=>
6t.id).sort().join("-"),r=q[l]||s.customers[0].id,d=z===r+"-"+s.customers[0].id;return e.jsxs("div",{className:"bg-white border-2 border-slate-900",children:[e.jsx("div",{className:"p-3 sm:p-4 border-b-2 border-slate-200 flex items-center justify-between",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`px-2 py-1 text-[9px] sm:text-[10px] font-bold uppercase tracking-wider border ${K(s.matchType)}`,children:T(s.matchType)}),e.jsxs("span",{className:"text-xs sm:text-sm font-bold",children:[s.customers.length," matches"]})]})}),e.jsxs("div",{className:"p-3 sm:p-4",children:[e.jsx("div",{className:"space-y-2 mb-4",children:s.customers.map(t=>e.jsx("div",{onClick:()=>C(a=>({...a,[l]:t.id})),className:`p-3 border-2 cursor-pointer transition-colors ${r===t.id?"border-slate-900 bg-slate-50":"border-slate-200 hover:border-slate-900"}`,children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`w-5 h-5 border-2 flex-shrink-0 mt-0.5 flex items-center justify-center ${r===t.id?"border-slate-900 bg-slate-900":"border-slate-300"}`,children:r===t.id&&e.jsx(y,{className:"w-3 h-3 text-white"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"font-bold text-sm sm:text-base",children:W(t)}),e.jsxs("div",{className:"mt-1 space-y-1",children:[t.phone&&e.jsxs("p",{className:"text-xs text-slate-500 flex items-center gap-1",children:[e.jsx(ee,{className:"w-3 h-3"})," ",t.phone]}),t.email&&e.jsxs("p",{className:"text-xs text-slate-500 flex items-center gap-1",children:[e.jsx(Y,{className:"w-3 h-3"})," ",t.email]}),(t.address||t.city)&&e.jsxs("p",{className:"text-xs text-slate-500 flex items-center gap-1",children:[e.jsx(Z,{className:"w-3 h-3"})," ",t.address||t.city]})]}),e.jsxs("p",{className:"text-[10px] text-slate-400 mt-1",children:["Added ",new Date(t.created_at).toLocaleDateString("en-GB",{day:"numeric",month:"short",year:"numeric"})]})]})]})},t.id))}),e.jsx("button",{onClick:()=>I(s,r),disabled:d,className:"w-full flex items-center justify-center gap-2 bg-slate-900 text-white px-4 py-3 font-bold uppercase tracking-wider text-xs sm:text-sm hover:bg-slate-800 transition-colors disabled:opacity-50",children:d?e.jsxs(e.Fragment,{children:[e.jsx(F,{className:"w-4 h-4 animate-spin"}),"Merging..."]}):e.jsxs(e.Fragment,{children:[e.jsx(se,{className:"w-4 h-4"}),"Merge into selected record"]})})]})]},l+i)})})]})]})})}export{re as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.