PageSourceSearch

https://app.bryxo.com/assets/ClientLayout-CwNbBFFY.js

js bryxo.com collected 2026-10-07 23:25:14 UTC 14,405 bytes, 1 lines download raw bytes

1import{r as i,j as e,h as it,u as ot,e as at,O as ct}from"./react-vendor-DQ70wdt-.js";import{u as lt,b as Re}from"./tanstack-BMTNuD0K.js";import{dh as ut,di as ke,dj as Ne,B as Z,J as mt,a4 as dt,dk as be,ag as D,a6 as pt,u as ht,ed as ft,a as Ct,b as gt,eH as xt,eI as yt,eB as vt,eJ as jt,cX as _t,a0 as P,eK as A,eL as ee,eM as St,eN as wt,eO as Et,eP as Rt,S as kt,L as Nt,ar as Ie,E as bt,ad as Me,X as It,j as Mt,k as Tt,l as Ot,x as Pt,m as At,n as Dt,eQ as Lt,A as te,y as Te,eR as Bt}from"./index-Cdzrkcn4.js";import{u as Ft}from"./useUnsavedChangesGuard-COXDjTz5.js";import{u as Ut}from"./useRecordGovernance-CnOdS386.js";import{u as qt}from"./useScrolledPast-6FEOWPsF.js";import{E as $t}from"./EmptyState-CgJzSFHJ.js";import{C as Qt,R as Oe,a as Yt,b as R,c as Ht,d as Vt,e as Wt}from"./ClientHeaderNewMenu-DIteY6ED.js";import{a as Pe,R as zt,T as Ae}from"./RecordIdentityBlock-Chtets5H.js";import"./scrollable-tabs-list-C5qqWJnE.js";import{B as Gt}from"./BookAppointmentDrawer-gPM3e-SJ.js";import{C as Kt}from"./CreateOpportunityDialog-C86j1QCx.js";import{C as Jt}from"./CreateEnquiryCaseDialog-BACgo9E4.js";import{R as Xt}from"./RecordMetadataFooter-BIpqtn7H.js";import{c as De}from"./slugGovernance-DkZBBr_m.js";import{C as Zt}from"./clientRecordContext-DRvf8PBN.js";import{f as en}from"./clientPrimaryContactGuard-BTXJWRFu.js";import{R as tn}from"./RelationshipConceptTooltip-D2owFRGS.js";import{S as Le,a as nn}from"./SameNameSoleTraderChip-B-fO0wRS.js";import{r as sn}from"./clientCommunicationRecipient-DtU80b_V.js";import{a as rn}from"./personIdentity-x_Oq57EP.js";import"./pdf-BgeYQNqi.js";import"./recharts-zAdsXJqR.js";import"./dnd-bjQMsJSd.js";import"./tiptap-BgkjLU8D.js";import"./radix-B9wVFvYu.js";import"./supabase-Dx5sNF5t.js";import"./CreateConversationDialog-C99wHJZv.js";import"./ContactSearchSelect-Bee90sgk.js";import"./useChannelAvailability-Cr4O14LI.js";import"./useChannelControl-PZMC5DZs.js";import"./SendWhatsAppDialog-Dpz2ToyL.js";import"./whatsappTemplateGate-D1BIVoLg.js";import"./shield-question-D3L5LINI.js";import"./shield-x-B_eB53rC.js";import"./whatsappTemplateRuntime-uZ0opH0s.js";import"./edgeError-B90rdgeI.js";import"./radio-group-lXxVFspa.js";import"./formatDistanceToNowStrict-oZcpKxWL.js";import"./compareAsc-DUahwLEk.js";import"./ManualNotificationSendDialog-8Vfy6XYx.js";import"./crown-DPJxHNqF.js";import"./user-x-DhYjS4Yw.js";import"./info-DWOOPV5l.js";import"./TaskFormDialog-B85sp36k.js";import"./ClientCombobox-Dp23r-SP.js";import"./EntityCombobox-B2_P9Ym4.js";import"./repeat-CYR0Y7B2.js";import"./LogTimelineEntryDrawer-CdXpOCDN.js";import"./timelineConstants-ChCyjQlH.js";import"./useSchedulingGovernance-BXbEsOjZ.js";import"./useAppointmentTypeLocations-B-Qx1Orm.js";import"./useMemberSchedulingProfile-BddGERAh.js";import"./useSchedulingSettings-CKH8Cdq_.js";import"./presenceStatus-BKUCoyMJ.js";import"./circle-check-big-B9_tgKzp.js";import"./laptop-jUmsVt9y.js";import"./circle-minus-DKvIlR1q.js";import"./bookingRequestKey-CYqaGhlE.js";import"./useWorkspaceDialCode-BJ4q3tw1.js";import"./chevron-left-BpV1gXL1.js";import"./usePipelines-yR_MAwVg.js";import"./useOpportunityMutations-C87F6Lxm.js";function on({email:p,clientId:m,contactId:x}){const[w,k]=i.useState(!1),[L,B]=i.useState(null),N=h=>{h.stopPropagation(),h.preventDefault(),pt(p),k(!0),setTimeout(()=>k(!1),1500)},C=!!m,a=h=>{h.stopPropagation(),C&&(h.preventDefault(),B({kind:"email"}))};return e.jsxs(ut,{delayDuration:200,children:[e.jsxs(ke,{children:[e.jsx(Ne,{asChild:!0,children:e.jsx(Z,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0 text-muted-foreground hover:text-foreground",onClick:N,"aria-label":w?"Copied":"Copy email",children:w?e.jsx(mt,{className:"h-2.5 w-2.5"}):e.jsx(dt,{className:"h-2.5 w-2.5"})})}),e.jsx(be,{side:"bottom",children:w?"Copied":"Copy email"})]}),e.jsxs(ke,{children:[e.jsx(Ne,{asChild:!0,children:C?e.jsx(Z,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0 text-muted-foreground hover:text-foreground",onClick:a,"aria-label":"New email",children:e.jsx(D,{className:"h-2.5 w-2.5"})}):e.jsx(Z,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0 text-muted-foreground hover:text-foreground",asChild:!0,"aria-label":"New email",children:e.jsx("a",{href:`mailto:${p}`,onClick:h=>h.stopPropagation(),children:e.jsx(D,{className:"h-2.5 w-2.5"})})})}),e.jsx(be,{side:"bottom",children:"New email"})]}),C&&e.jsx(Qt,{intent:L,onClose:()=>B(null),clientId:m,contactId:x??null})]})}const an=["prospect","onboarding","active","at_risk","lapsed","offboarded"],cn=["not_started","in_progress","blocked","waiting_on_client","awaiting_review","approved","draft"],ln=new Set(["limited_company","llp","partnership","charity","trust","other","sole_trader"]),Be=p=>(p??"").trim().toLowerCase(),f=[];function ys(){var _e,Se,we,Ee;const{id:p}=it(),{workspaceId:m,workspaceSlug:x,isAdmin:w,isWorkspaceFeatureEnabled:k}=ht(),{can:L}=ft(),{user:B}=Ct(),{members:N}=gt(),C=ot(),a=at(),h=(_e=xt())==null?void 0:_e.registerScreenContext,b=yt(),{recordRecentAccess:ne,selectedClient:F}=vt(),se=lt(),U=i.useRef(null),re=qt(U),[ie,q]=i.useState(!1),[oe,ae]=i.useState(!1),[ce,le]=i.useState(!1),ue=i.useRef(!1),me=i.useRef(!1),de=i.useRef(!1);ie&&(ue.current=!0),oe&&(me.current=!0),ce&&(de.current=!0);const[pe,Fe]=i.useState({}),Ue=Object.values(pe).some(Boolean);Ft(Ue);const qe=i.useCallback((n,r)=>{Fe(o=>({...o,[n]:r}))},[]),S=Re({queryKey:["client-resolve",m??null,p??null],enabled:!!p&&!!m,staleTime:5*6e4,queryFn:async()=>{const n=await Te.rpc("resolve_firm_record_slug",{p_workspace_ref:x??m,p_client_ref:p,p_entity_ref:null}).maybeSingle();if(n.error)throw n.error;const r=n.data,o=(r==null?void 0:r.workspace_slug)??x,l=r==null?void 0:r.client_slug;return{clientId:(r==null?void 0:r.client_id)??null,canonical:o&&l?{wsSlug:o,clientSlug:l}:null}}}),y=((Se=S.data)==null?void 0:Se.clientId)??null,he=i.useMemo(()=>["client-record",m??null,y],[m,y]),v=Re({enabled:!!y&&!!m,...Lt(m,y)}),s=v.data??null,$e=S.isPending||!!y&&(v.isPending||!s&&v.isFetching);i.useEffect(()=>{y&&ne(y)},[y,ne]),i.useEffect(()=>{if(!(s!=null&&s.client))return;const n=requestAnimationFrame(()=>requestAnimationFrame(jt));return()=>cancelAnimationFrame(n)},[s==null?void 0:s.client]);const t=(s==null?void 0:s.client)??null,Qe=k("enquiries")&&L(_t.ENQUIRY_MANAGE),d=(s==null?void 0:s.entities)??f,I=(s==null?void 0:s.contacts)??f,$=I.length,Ye=(s==null?void 0:s.contactEntityLinks)??f,Q=(s==null?void 0:s.contactLinkedEntities)??f,Y=(s==null?void 0:s.services)??f,H=(s==null?void 0:s.compliance)??f,V=(s==null?void 0:s.tasks)??f,W=(s==null?void 0:s.documents)??f,He=(s==null?void 0:s.invoices)??f,Ve=(s==null?void 0:s.typeCodes)??f,u=(s==null?void 0:s.primaryContact)??null,E=(s==null?void 0:s.resourceErrors)??{compliance:null,tasks:null,invoices:null,primaryContact:null},M=((we=S.data)==null?void 0:we.canonical)??null,c=i.useCallback(n=>r=>{se.setQueryData(he,o=>{if(!o)return o;const l=typeof r=="function"?r(o[n]):r;return{...o,[n]:l}})},[se,he]),T=i.useMemo(()=>c("client"),[c]),fe=i.useMemo(()=>c("entities"),[c]),We=i.useMemo(()=>c("contacts"),[c]),ze=i.useMemo(()=>c("services"),[c]),Ge=i.useMemo(()=>c("compliance"),[c]),Ke=i.useMemo(()=>c("tasks"),[c]),Je=i.useMemo(()=>c("documents"),[c]),Xe=i.useMemo(()=>c("invoices"),[c]),Ze=i.useCallback(()=>{v.refetch()},[v]);i.useEffect(()=>{var o;if(!M)return;const n=P.firm.clientSlug(M.wsSlug,M.clientSlug);
1if(a.pathname.startsWith(n))return;const r=((o=A(a.pathname))==null?void 0:o.tail)??"";C(ee(n+r,a.search,a.hash),{replace:!0})},[M,a.hash,a.pathname,a.search,C]);const{updateRecord:Ce}=Ut(),z=async(n,r)=>{var l;if(!t||!m)return;if(n==="slug"){const _=await De("client",t.id,r);if(T({...t,slug:_.slug}),te("Updated"),x){const g=((l=A(a.pathname))==null?void 0:l.tail)??"/overview";C(ee(P.firm.clientSlug(x,_.slug)+g,a.search,a.hash),{replace:!0})}return!0}return await Ce("client",t.id,{[n]:r})?(T({...t,[n]:r}),te("Updated"),!0):!1},et=async n=>{var _;if(!t||!m)throw new Error("No client loaded");const{slug:r,...o}=n;let l;if(r!==void 0&&(l=(await De("client",t.id,r)).slug),Object.keys(o).length>0&&!await Ce("client",t.id,o))throw new Error("Governance update failed");if(T(g=>g&&{...g,...o,...l?{slug:l}:{}}),l&&x){const g=((_=A(a.pathname))==null?void 0:_.tail)??"/overview";C(ee(P.firm.clientSlug(x,l)+g,a.search,a.hash),{replace:!0})}},tt=i.useCallback(async()=>{var r;const n=(r=s==null?void 0:s.client)==null?void 0:r.id;n&&c("primaryContact")(await St(n))},[(Ee=s==null?void 0:s.client)==null?void 0:Ee.id,c]),nt=async()=>{if(!(t!=null&&t.id))return;const{data:n,error:r}=await Te.from("v_entities_safe").select("*").eq("client_id",t.id).order("created_at");if(r){console.error("[client-record] entity refresh failed",r),te.error("Couldn't refresh entities");return}fe(n??[])},j=i.useMemo(()=>{var n;return!!((n=wt(a.pathname))!=null&&n.clientRef)},[a.pathname]),ge=i.useMemo(()=>{var l;if(!(t!=null&&t.id)||j)return null;const r=(((l=A(a.pathname))==null?void 0:l.tail)??"/overview").split("/").filter(Boolean)[0]??"overview",o=Et.find(_=>_.path===r);return Rt(a.pathname,`firm.client.${(o==null?void 0:o.path)??"overview"}`,[{type:"client",id:t.id,label:t.name}])},[t==null?void 0:t.id,t==null?void 0:t.name,j,a.pathname]);i.useEffect(()=>{h&&h(ge)},[ge,h]);const xe=i.useMemo(()=>!s||j?null:{entities:d.length,contacts:$,work:E.compliance||E.tasks?void 0:H.length+V.filter(n=>cn.includes(n.status)).length,commercial:Y.length,documents:W.length},[H.length,$,s,W.length,d.length,j,E.compliance,E.tasks,Y.length,V]);i.useEffect(()=>{if(b)return b(xe),()=>b(null)},[xe,b]);const ye=t?N.find(n=>n.user_id===t.owner_id):null,G=i.useMemo(()=>{const n=d.map(o=>o.legal_name).filter(Boolean);if(n.length===0)return null;const r=n.slice(0,2).join(", ");return n.length>2?`${r} +${n.length-2}`:r},[d]),ve=i.useMemo(()=>{const n=new Set(d.map(r=>r.id));return Q.filter(r=>(r==null?void 0:r.id)&&!n.has(r.id)).length},[Q,d]),je=i.useMemo(()=>{if(!t)return null;const n=d.find(r=>ln.has(r.entity_type??"")&&Be(r.legal_name)===Be(t.name));return n?n.entity_type==="sole_trader"?Le:`Client name matches linked ${String(n.entity_type??"entity").replace(/_/g," ")}`:null},[t,d]),O=i.useMemo(()=>en(u,d),[u,d]),K=je===Le||(O==null?void 0:O.entity_type)==="sole_trader",J=i.useMemo(()=>sn({client:t,primaryContact:u,contacts:I}),[t,u,I]),st=n=>{if(!n)return null;try{return new Date(n).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"})}catch{return n}};
1if($e){const n=Bt(p),r=(F==null?void 0:F.name)??(p&&!n?p.replace(/-/g," "):p??"");return e.jsxs(e.Fragment,{children:[!j&&e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:U,className:"h-px","aria-hidden":"true"}),e.jsx(Oe,{sticky:!0,condensed:re,className:"space-y-2 px-4 py-2 md:px-6",identity:e.jsx(Pe,{name:r})})]}),e.jsx("div",{className:"p-4 md:p-6",children:e.jsx(kt,{"aria-label":"Loading client panel",className:"h-64 w-full"})})]})}const X=S.error??v.error;if(X)return e.jsx("div",{className:"p-4 md:p-6",children:e.jsx(Nt,{title:"Couldn't load client",message:X instanceof Error?X.message:"The client record could not be loaded.",onRetry:()=>{S.error?S.refetch():v.refetch()}})});if(!t)return e.jsx("div",{className:"p-4 md:p-6",children:e.jsx($t,{title:"Client not found",description:"This client doesn't exist or you don't have access."})});t.type==="individual"||(t.type??"").replace(/_/g," ");const rt=rn(t,u);return e.jsxs(Zt.Provider,{value:{client:t,setClient:T,entities:d,setEntities:fe,contacts:I,setContacts:We,contactCount:$,contactEntityLinks:Ye,contactLinkedEntities:Q,services:Y,setServices:ze,compliance:H,setCompliance:Ge,tasks:V,setTasks:Ke,documents:W,setDocuments:Je,invoices:He,setInvoices:Xe,typeCodes:Ve,primaryContact:u,resourceErrors:E,retryResourceData:Ze,members:N,updateField:z,saveClientFields:et,refreshEntities:nt,dirtySections:pe,handleSectionDirtyChange:qe,refreshPrimaryContact:tt},children:[!j&&e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:U,className:"h-px","aria-hidden":"true"}),e.jsx(Oe,{sticky:!0,condensed:re,className:"space-y-2 px-4 py-2 md:px-6",identity:e.jsx(Pe,{icon:t.type==="individual"?e.jsx(Ie,{className:"h-6 w-6"}):e.jsx(Me,{className:"h-6 w-6"}),name:t.name,nameAdornment:e.jsx(tn,{concept:"client"}),onRename:async n=>{await z("name",n)},chips:e.jsxs(e.Fragment,{children:[t.client_id_code&&e.jsx(zt,{copyValue:t.client_id_code,children:t.client_id_code}),K&&e.jsx(nn,{}),je&&!K&&e.jsx(Ae,{children:"Identity review"}),O&&!K&&e.jsx(Ae,{children:"Primary contact review"})]})}),actions:e.jsx(Ht,{comms:e.jsxs(e.Fragment,{children:[e.jsx(Vt,{clientId:t.id,workspaceId:m,variant:"default",primaryContactId:u==null?void 0:u.id,clientName:t.name,onCreateOpportunity:()=>ae(!0),onCreateClearance:Qe?()=>le(!0):void 0,clearanceRecommended:t.lifecycle_status==="prospect"||t.lifecycle_status==="onboarding"}),e.jsx(Wt,{clientId:t.id,variant:"ghost",clientEmail:J.email,clientPhone:J.phone,contactId:J.contactId,notify:{clientId:t.id,isAdmin:w,workspaceId:m??void 0,clientName:t.name},onBookAppointment:()=>q(!0)})]}),state:e.jsxs(Mt,{value:t.lifecycle_status,onValueChange:n=>z("lifecycle_status",n),children:[e.jsx(Tt,{className:"h-8 w-auto min-w-24 gap-1.5 text-xs","aria-label":"Status",children:e.jsx(Ot,{children:e.jsx(Pt,{status:t.lifecycle_status})})}),e.jsx(At,{children:an.map(n=>e.jsx(Dt,{value:n,className:"text-xs capitalize",children:n.replace(/_/g," ")},n))})]})}),meta:e.jsxs(Yt,{children:[ye&&e.jsx(R,{icon:e.jsx(Ie,{}),label:"Owner",value:ye.full_name??"—"}),u&&!rt&&e.jsx(R,{icon:e.jsx(D,{}),label:"Primary",value:bt(u)||"—",onClick:()=>C(P.firm.contact(u.id),{state:{fromClient:t.id}})}),t.email&&e.jsx(R,{icon:e.jsx(D,{}),value:t.email,fullText:t.email,truncate:!1,hoverActions:e.jsx(on,{email:t.email,clientId:t.id,contactId:u==null?void 0:u.id})}),e.jsx(R,{icon:e.jsx(Me,{}),label:"Entities",value:ve>0?`${d.length} owned · ${ve} via contacts`:G?`${d.length}: ${G}`:String(d.length),fullText:G??void 0}),t.created_at&&e.jsx(R,{icon:e.jsx(It,{}),label:"Created",value:st(t.created_at)})]})})]}),e.jsx(ct,{}),!j&&e.jsx("div",{className:"px-4 md:px-6 pb-6",children:e.jsx(Xt,{bryxoId:t.bryxo_id})}),ue.current&&e.jsx(Gt,{open:ie,onOpenChange:q,onBooked:()=>q(!1),prefillClientId:t.id}),me.current&&e.jsx(Kt,{open:oe,onOpenChange:ae,defaultClientId:t.id}),de.current&&e.jsx(Jt,{open:ce,onOpenChange:le,defaultClientId:t.id,defaultClientName:t.name})]})}export{ys 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.