1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9076],{10240:(e,t,s)=>{s.d(t,{O4:()=>r,PT:()=>i,Zj:()=>a});let n=[10,1,3,5,7,9,11,13,15,17,19];function a(e){return e.replace(/\D/g,"")}function r(e){if(!/^[1-9][0-9]{10}$/.test(e))return!1;let t=0;for(let s=0;s<n.length;s++){let a=e.charCodeAt(s)-48;t+=(0===s?a-1:a)*n[s]}return t%89==0}function i(e){let t=a(e);return 11!==t.length?e:`${t.slice(0,2)} ${t.slice(2,5)} ${t.slice(5,8)} ${t.slice(8)}`}},12651:(e,t,s)=>{s.d(t,{A:()=>n});let n=(0,s(78340).A)("CircleCheck",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]])},13909:(e,t,s)=>{s.d(t,{Bs:()=>l,Cc:()=>p,HC:()=>c,Wh:()=>d,aF:()=>o,at:()=>h,bz:()=>g,tE:()=>m,tV:()=>u,vV:()=>x});let n=new Intl.NumberFormat("en-US",{style:"currency",currency:"AUD",minimumFractionDigits:2,maximumFractionDigits:2}),a=new Intl.NumberFormat("en-US",{style:"currency",currency:"AUD",notation:"compact",maximumFractionDigits:1}),r=new Intl.NumberFormat("en-AU"),i=new Intl.NumberFormat("en-AU",{notation:"compact",maximumFractionDigits:1});function l(e){return n.format((e||0)/100)}function o(e){let t=(e||0)/100;return Math.abs(t)>=1e3?a.format(t):n.format(t)}function d(e){return r.format(Math.round(e||0))}function c(e){return Math.abs(e)>=1e4?i.format(e):r.format(Math.round(e||0))}function m(e){return new Date(`${e}T00:00:00Z`).toLocaleDateString("en-AU",{day:"numeric",month:"short",timeZone:"UTC"})}function u(e){return new Date(`${e}T00:00:00Z`).toLocaleDateString("en-AU",{weekday:"short",day:"numeric",month:"short",year:"numeric",timeZone:"UTC"})}function h(e,t=3){if(!(e>0))return[0,1];let s=e/t,n=10**Math.floor(Math.log10(s)),a=[1,2,2.5,5,10].map(e=>e*n).find(e=>e>=s)??s;return Array.from({length:t+1},(e,t)=>t*a)}function p(e,t){return Number.isFinite(t)&&0!==t?(e-t)/Math.abs(t)*100:null}function x(e){let t=Math.round(e||0),s=Math.abs(t),n=(e,t)=>e.toLocaleString("en-AU",{maximumFractionDigits:t});return s>=1e9?`${n(t/1e9,1)}B`:s>=1e6?`${n(t/1e6,s>=1e8?0:1)}M`:s>=1e3?`${n(t/1e3,0)}K`:n(t,0)}function g(e){return`${x(e)} credits`}},19029:(e,t,s)=>{s.d(t,{w:()=>v});var n=s(95155),a=s(12115),r=s(55711),i=s(6296),l=s(66609),o=s(87757),d=s(53487),c=s(61732),m=s(13909),u=s(45160),h=s(89239),p=s(42763),x=s(60529),g=s(27529),f=s(40980);let b={commission:"Commission",bonus:"Bonus",adjustment:"Adjustment",clawback:"Clawback"},w={pending_approval:"Awaiting approval",payable:"Not sent yet",transferring:"Sending",transferred:"Sent",void:"Cancelled",open:"Owed back",settled:"Recovered"};function j(e){let t=null!=e.charge_amount_cents?` of the ${(0,m.Bs)(e.charge_amount_cents)} the client paid`:"";switch(e.review_state){case"dispute":return{label:"Disputed",detail:`The client disputed this payment with their bank${e.dispute_status?` (${e.dispute_status.replace(/_/g," ")})`:""}.`};case"refund":return{label:"Refunded",detail:`${(0,m.Bs)(e.refunded_cents)}${t} has been refunded.`};default:return{label:"Details need checking",detail:"The payment's details couldn't be matched to a plan or a setup fee, so nothing has been worked out from it with confidence."}}}let y=e=>"pending_approval"===e||"payable"===e;function v({partner:e,onChanged:t}){let{data:s,loading:i,failed:p,migrationRequired:x,reload:N}=(0,o.aV)("/api/admin/partners/reviews","the reviews"),[S,$]=(0,a.useState)(null),[T,C]=(0,a.useState)(null),[A,B]=(0,a.useState)(null);async function R(){await N(),await t?.()}if(x&&!s)return(0,n.jsx)(o.I,{});let D=s?.reviews??[],G=(s?.clawbacks??[]).filter(t=>!e||t.partner_id===e.id),O=[...G].sort((e,t)=>Number("open"===t.state)-Number("open"===e.state)||t.created_at.localeCompare(e.created_at)),M=G.filter(e=>"open"===e.state).length,P=G.reduce((e,t)=>e+("open"===t.state?Math.max(0,t.amount_cents-t.settled_cents):0),0);return(0,n.jsxs)("div",{className:(0,f.cn)("space-y-4 transition-opacity",i&&s&&"opacity-60"),children:[!e&&(0,n.jsx)(c.Panel,{title:`Needs review${D.length?` (${(0,m.Wh)(D.length)})`:""}`,description:"Client payments that were refunded, disputed or need checking. Their lines aren't sent until someone resolves the payment here.",flush:!0,children:!s&&p?(0,n.jsx)("div",{className:"border-t",children:(0,n.jsx)(d.mz,{what:"the payments under review",onRetry:()=>void N()})}):s?D.length?(0,n.jsx)("ul",{className:"divide-y border-t",children:D.map(e=>{let t=j(e);return(0,n.jsxs)("li",{className:"px-5 py-4",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-x-4 gap-y-2",children:[(0,n.jsxs)("div",{className:"min-w-0 flex-1 basis-64",children:[(0,n.jsxs)("p",{className:"flex flex-wrap items-center gap-2 text-sm font-medium",children:[e.client_name,(0,n.jsx)(u.E,{variant:"data"===e.review_state?"warning":"destructive",children:t.label})]}),(0,n.jsx)("p",{className:"mt-0.5 text-xs text-muted-foreground",children:t.detail}),(0,n.jsx)("p",{className:"mt-0.5 truncate font-mono text-[11px] text-muted-foreground",children:e.invoice_id})]}),(0,n.jsx)(h.$,{size:"sm",onClick:()=>$(e),children:"Resolve"})]}),e.lines.length?(0,n.jsx)("ul",{className:"mt-3 divide-y rounded-lg border text-sm",children:e.lines.map(e=>(0,n.jsxs)("li",{className:"flex flex-wrap items-center gap-x-4 gap-y-1 px-3 py-2",children:[(0,n.jsxs)("span",{className:"min-w-0 flex-1 basis-4
10 truncate",children:[e.partner_name," ",(0,n.jsxs)("span",{className:"text-muted-foreground",children:["\xb7 ",b[e.kind]??e.kind]})]}),(0,n.jsx)(u.E,{variant:"transferred"===e.state?"success":"void"===e.state?"muted":"outline",children:w[e.state]??e.state}),(0,n.jsx)("span",{className:"w-28 text-right tabular-nums",children:(0,m.Bs)(e.total_cents)}),(0,n.jsx)("span",{className:"w-44 text-right text-xs text-muted-foreground",children:e.suggested_clawback_cents>0?`Suggested clawback ${(0,m.Bs)(e.suggested_clawback_cents)}`:y(e.state)?"Not sent: can be cancelled":""})]},e.id))}):(0,n.jsx)("p",{className:"mt-3 text-xs text-muted-foreground",children:"No partner line was created from this payment."})]},e.invoice_id)})}):(0,n.jsx)("p",{className:"border-t px-5 py-8 text-center text-sm text-muted-foreground",children:"No payment is waiting for review."}):(0,n.jsx)(o._N,{className:"border-t",rows:2})}),(0,n.jsx)(c.Panel,{title:`${e?"Owes back":"Clawbacks"}${M?` (${(0,m.Wh)(M)} open)`:""}`,description:P>0?`${(0,m.Bs)(P)} is still owed back. It comes off ${e?"their":"each partner's"} following payments on its own until it is recovered.`:e?"Money this partner owes back after a refund or dispute. An open clawback comes off their following payments on its own.":"Money a partner owes back after a refund or dispute. An open clawback comes off that partner's following payments on its own.",flush:!0,children:!s&&p?(0,n.jsx)("div",{className:"border-t",children:(0,n.jsx)(d.mz,{what:"the clawbacks",onRetry:()=>void N()})}):s?O.length?(0,n.jsx)("ul",{className:"divide-y border-t",children:O.map(t=>{let s=Math.max(0,t.amount_cents-t.settled_cents),a="open"===t.state;return(0,n.jsxs)("li",{className:"flex flex-wrap items-center gap-x-4 gap-y-2 px-5 py-3 text-sm",children:[(0,n.jsxs)("span",{className:"min-w-0 flex-1 basis-56",children:[(0,n.jsx)("span",{className:"block truncate font-medium",children:e?t.client_name:t.partner_name}),(0,n.jsxs)("span",{className:"block truncate text-xs text-muted-foreground",title:t.note??void 0,children:[e?"":`${t.client_name} \xb7 `,(0,o.XV)(t.created_at),t.note?` \xb7 ${t.note}`:""]})]}),(0,n.jsxs)("span",{className:"w-40 text-right tabular-nums",children:[(0,n.jsx)("span",{className:(0,f.cn)("block","void"===t.state&&"text-muted-foreground line-through"),children:(0,m.Bs)(t.amount_cents)}),(0,n.jsx)("span",{className:"block text-xs text-muted-foreground",children:"settled"===t.state?"Recovered in full":"void"===t.state?`Written off${t.settled_cents?`, ${(0,m.Bs)(t.settled_cents)} recovered`:""}`:t.settled_cents?`${(0,m.Bs)(t.settled_cents)} recovered, ${(0,m.Bs)(s)} to go`:"Nothing recovered yet"})]}),(0,n.jsx)("span",{className:"flex w-full justify-end gap-2 sm:w-56",children:a?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(h.$,{size:"sm",variant:"ghost",onClick:()=>B(t),children:"Write off"}),(0,n.jsxs)(h.$,{size:"sm",variant:"outline",disabled:!t.can_reverse,title:t.can_reverse?void 0:"There is no Stripe transfer to pull back from. It is recovered from their following payments.",onClick:()=>C(t),children:[(0,n.jsx)(r.A,{}),"Pull back now"]})]}):(0,n.jsx)(u.E,{variant:"settled"===t.state?"success":"muted",children:"settled"===t.state?"Recovered":"Written off"})})]},t.id)})}):(0,n.jsx)("p",{className:"border-t px-5 py-8 text-center text-sm text-muted-foreground",children:e?"They owe nothing back.":"No partner owes anything back."}):(0,n.jsx)(o._N,{className:"border-t",rows:2})}),(0,n.jsx)(_,{review:S,onOpenChange:e=>!e&&$(null),onDone:R}),(0,n.jsx)(k,{clawback:T,onOpenChange:e=>!e&&C(null),onDone:R}),(0,n.jsx)(o.Lg,{open:!!A,onOpenChange:e=>!e&&B(null),title:`Write off what ${A?.partner_name??"this partner"} owes?`,description:A?`${(0,m.Bs)(Math.max(0,A.amount_cents-A.settled_cents))} is still to be recovered for ${A.client_name}. Writing it off stops it coming off their payments; ETEC+ carries the loss. What was already recovered stays recovered. This can't be undone.`:void 0,notePlaceholder:"e.g. Partner has left, amount too small to chase",confirmText:"Write off",destructive:!0,onSubmit:async(e,t)=>{A&&(await (0,g.nr)(`/api/admin/partners/ledger/${A.id}/write-off`,{method:"POST",body:JSON.stringify({note:e,request_id:t})}),l.oR.success("Clawback written off."),await R())}})]})}function _({review:e,onOpenChange:t,onDone:s}
1){let[r,i]=(0,a.useState)(!1);return(0,n.jsx)(p.lG,{open:!!e,onOpenChange:e=>!r&&t(e),children:(0,n.jsx)(p.Cf,{className:"sm:max-w-xl",children:e&&(0,n.jsx)(N,{review:e,busy:r,setBusy:i,onClose:()=>t(!1),onDone:s},e.invoice_id)})})}function N({review:e,busy:t,setBusy:s,onClose:r,onDone:d}){let[c]=(0,a.useState)(()=>crypto.randomUUID()),u=(0,a.useId)(),f=e.lines.filter(e=>"transferred"===e.state),w=e.lines.filter(e=>y(e.state)),v=e.lines.filter(e=>"transferring"===e.state).length,[_,k]=(0,a.useState)(w.length&&"data"!==e.review_state?"void_unsent":"release"),[S,$]=(0,a.useState)(()=>Object.fromEntries(f.map(e=>[e.id,(0,o.s7)(e.suggested_clawback_cents)]))),[T,C]=(0,a.useState)(""),[A,B]=(0,a.useState)(!1),[R,D]=(0,a.useState)(null),G=f.map(e=>(0,o.ob)(S[e.id]??"")),O=f.map((e,t)=>null===G[t]?"Enter an amount, or 0 for none.":(G[t]??0)>e.total_cents?`No more than the ${(0,m.Bs)(e.total_cents)} that was sent.`:null),M=G.reduce((e,t)=>e+(t??0),0),P=O.every(e=>!e)&&T.trim().length>0&&0===v,U=j(e);async function z(){if(P&&!t){s(!0),D(null);try{let t={action:_,clawbacks:f.map((e,t)=>({line_id:e.id,amount_cents:G[t]??0})).filter(e=>e.amount_cents>0),note:T.trim(),request_id:c};await (0,g.nr)(`/api/admin/partners/reviews/${encodeURIComponent(e.invoice_id)}`,{method:"POST",body:JSON.stringify(t)}),l.oR.success(`Review of ${e.client_name}'s payment resolved.`),r(),await d()}catch(e){D(e.message),B(!1)}finally{s(!1)}}}let E=["void_unsent"===_&&w.length?`${(0,m.Wh)(w.length)} unsent ${1===w.length?"line is":"lines are"} cancelled`:w.length?`${(0,m.Wh)(w.length)} unsent ${1===w.length?"line goes":"lines go"} ahead`:null,M>0?`${(0,m.Bs)(M)} becomes owed back`:f.length?"nothing is taken back":null].filter(Boolean);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(p.c7,{children:[(0,n.jsxs)(p.L3,{children:["Resolve ",e.client_name,"'s payment"]}),(0,n.jsxs)(p.rr,{children:[U.detail," Decide what happens to the lines it produced. The payment then leaves the review list."]})]}),(0,n.jsxs)("form",{className:"space-y-5",onSubmit:e=>{e.preventDefault(),A?z():P&&B(!0)},children:[(0,n.jsxs)("fieldset",{className:"space-y-2",children:[(0,n.jsxs)("legend",{className:"text-sm font-medium",children:["Lines not sent yet ",(0,n.jsxs)("span",{className:"font-normal text-muted-foreground",children:["(",(0,m.Wh)(w.length),")"]})]}),w.length?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("label",{className:"flex cursor-pointer items-start gap-2.5 rounded-lg border p-3 text-sm has-[:checked]:border-foreground",children:[(0,n.jsx)("input",{type:"radio",name:u,className:"mt-1",checked:"void_unsent"===_,onChange:()=>{k("void_unsent"),B(!1)},disabled:t}),(0,n.jsxs)("span",{children:[(0,n.jsx)("span",{className:"block font-medium",children:"Cancel them"}),(0,n.jsxs)("span",{className:"block text-xs text-muted-foreground",children:["The client's money came back, so the partners aren't paid for it. ",(0,m.Bs)(w.reduce((e,t)=>e+t.total_cents,0))," is cancelled."]})]})]}),(0,n.jsxs)("label",{className:"flex cursor-pointer items-start gap-2.5 rounded-lg border p-3 text-sm has-[:checked]:border-foreground",children:[(0,n.jsx)("input",{type:"radio",name:u,className:"mt-1",checked:"release"===_,onChange:()=>{k("release"),B(!1)},disabled:t}),(0,n.jsxs)("span",{children:[(0,n.jsx)("span",{className:"block font-medium",children:"Let them go ahead"}),(0,n.jsx)("span",{className:"block text-xs text-muted-foreground",children:"The payment stands (a small refund, a dispute that was won). They are sent on the next pay run. The same refund won't flag this payment again; a further one will."})]})]})]}):(0,n.jsx)("p",{className:"text-xs text-muted-foreground",children:"None. The review is closed, and the same refund won't flag this payment again."}),v>0&&(0,n.jsxs)("p",{className:"text-xs text-warning",children:[(0,m.Wh)(v)," ",1===v?"line is":"lines are"," being sent right now and can't be cancelled, so this review can't be closed yet. Reload in a few minutes: if it was sent it will be listed below to take back, and if not it can be cancelled with the rest."]})]}),f.length>0&&(0,n.jsxs)("fieldset",{className:"space-y-2",children:[(0,n.jsxs)("legend",{className:"text-sm font-medium",children:["Lines already sent ",(0,n.jsxs)("span",{className:"font-normal text-muted-foreground",children:["(",(0,m.Wh)(f.length),")"]})]}),(0,n.jsx)("p",{className:"text-xs text-muted-foreground",children:"The amount each partner owes back, GST included. It comes off their following payments until it is recovered, or you can pull it back from their Stripe balance afterwards. Enter 0 to take nothing back."}),f.map((e,s)=>(0,n.jsxs)("label",{className:"flex flex-wrap items-center justify-between gap-x-4 gap-y-1 text-sm",children:[(0,n.jsxs)("span",{className:"min-w-0 flex-1",children:[(0,n.jsx)("span",{className:"block truncate font-medium",children:e.partner_name}),(0,n.jsxs)("span",{className:"block text-xs font-normal text-muted-foreground",children:[b[e.kind]??e.kind," \xb7 ",(0,m.Bs)(e.total_cents)," sent",O[s]?(0,n.jsxs)("span",{className:"text-destructive",children:[" \xb7 ",O[s]]}):null]})]}),(0,n.jsxs)("span",{className:"flex items-center gap-1.5",children:[(0,n.jsx)("span",{className:"text-xs text-muted-foreground",children:"A$"}),(0,n.jsx)(x.p,{className:"w-28 text-right tabular-nums",inputMode:"decimal",value:S[e.id]??"",onChange:t=>{B(!1),$(s=>({...s,[e.id]:t.target.value}))},disabled:t,"aria-label":`Clawback from ${e.partner_name}`,"aria-invalid":!!O[s]})]})]},e.id))]}),(0,n.jsx)(o.Tq,{label:"Why",value:T,onChange:e=>{C(e),B(!1)},placeholder:"e.g. Full refund on 3 Oct, client cancelled inside the first week",disabled:t}),(0,n.jsx)(o.lZ,{message:R}),A&&(0,n.jsxs)("p",{className:"rounded-lg border border-warning-border bg-warning-surface px-3 py-2 text-sm",children:[E.length?`${E.join(", ")}. `:"The review is closed and nothing else changes. ","This can't be und
1one from here."]}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(h.$,{type:"button",variant:"outline",onClick:r,disabled:t,children:"Cancel"}),(0,n.jsxs)(h.$,{type:"submit",variant:"void_unsent"===_&&w.length?"destructive":"default",disabled:t||!P,children:[t&&(0,n.jsx)(i.A,{className:"animate-spin"}),A?"Confirm":"Resolve"]})]})]})]})}function k({clawback:e,onOpenChange:t,onDone:s}){let[r,i]=(0,a.useState)(!1);return(0,n.jsx)(p.lG,{open:!!e,onOpenChange:e=>!r&&t(e),children:(0,n.jsx)(p.Cf,{className:"sm:max-w-md",children:e&&(0,n.jsx)(S,{clawback:e,busy:r,setBusy:i,onClose:()=>t(!1),onDone:s},e.id)})})}function S({clawback:e,busy:t,setBusy:s,onClose:r,onDone:d}){let[c,u]=(0,a.useState)(()=>crypto.randomUUID()),b=Math.max(0,e.amount_cents-e.settled_cents),[w,j]=(0,a.useState)(()=>(0,o.s7)(b)),[y,v]=(0,a.useState)(null),_=(0,o.ob)(w),N=null!==_&&_>0&&_<=b;async function k(){if(N&&!t&&null!==_){s(!0),v(null);try{let t=await (0,g.nr)(`/api/admin/partners/ledger/${e.id}/reverse`,{method:"POST",body:JSON.stringify({..._<b?{amount_cents:_}:{},request_id:c})});t.reversed?l.oR.success(`${(0,m.Bs)(t.cents??_)} pulled back from ${e.partner_name}.`):l.oR.warning(t.message??"Stripe didn't answer. The pull-back is still being confirmed; check again in a few minutes."),r(),await d()}catch(e){v(e.message)}finally{s(!1)}}}return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(p.c7,{children:[(0,n.jsxs)(p.L3,{children:["Pull back from ",e.partner_name," now?"]}),(0,n.jsxs)(p.rr,{children:["This reverses the Stripe transfer for ",e.client_name,", taking the money out of the partner's Stripe balance straight away. It only works while the money is still there: once it has been paid out to their bank, Stripe refuses, and the amount comes off their following payments instead."]})]}),(0,n.jsxs)("form",{className:"space-y-5",onSubmit:e=>{e.preventDefault(),k()},children:[(0,n.jsxs)("label",{className:"block text-sm font-medium",children:["Amount to pull back",(0,n.jsxs)("span",{className:"mt-1.5 flex items-center gap-1.5",children:[(0,n.jsx)("span",{className:"text-xs font-normal text-muted-foreground",children:"A$"}),(0,n.jsx)(x.p,{className:"w-36 text-right tabular-nums",inputMode:"decimal",value:w,onChange:e=>{j(e.target.value),y&&u(crypto.randomUUID()),v(null)},disabled:t,"aria-invalid":!N,autoFocus:!0})]}),(0,n.jsx)("span",{className:(0,f.cn)("mt-1.5 block text-xs font-normal",N?"text-muted-foreground":"text-destructive"),children:N?`${(0,m.Bs)(b)} is still owed back.`:`Enter an amount up to the ${(0,m.Bs)(b)} still owed back.`})]}),(0,n.jsx)(o.lZ,{message:y}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(h.$,{type:"button",variant:"outline",onClick:r,disabled:t,children:y?"Close":"Cancel"}),(0,n.jsxs)(h.$,{type:"submit",variant:"destructive",disabled:t||!N,children:[t&&(0,n.jsx)(i.A,{className:"animate-spin"}),"Pull back ",N&&null!==_?(0,m.Bs)(_):""]})]})]})]})}},20986:(e,t,s)=>{s.d(t,{A:()=>n});let n=(0,s(78340).A)("RotateCw",[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]])},21628:(e,t,s)=>{s.d(t,{A:()=>n});let n=(0,s(78340).A)("ArrowRight",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]])},48875:(e,t,s)=>{s.d(t,{aP:()=>$,NY:()=>_,Zr:()=>S,zc:()=>y,JO:()=>j,p$:()=>N});var n=s(95155),a=s(12115),r=s(41585),i=s(24384),l=s(12651),o=s(6296);let d=(0,s(78340).A)("SearchCheck",[["path",{d:"m8 11 2 2 4-4",key:"1sed1v"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);var c=s(66609),m=s(83740),u=s(83765),h=s(61732),p=s(45160),x=s(89239),g=s(27529),f=s(10240),b=s(80813),w=s(40980);function j(e){return!!(e.abr_checked_at&&e.abr_result)}function y(e){return j(e)?`As they declared it, beside what the Australian Business Register said when it was last asked (${(0,h.BM)(e.abr_checked_at)}).`:"As they declared it. The ABN passed its checksum; it hasn't been checked with the Australian Business Register yet."}function v(e){if(!e)return"";let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleDateString("en-AU",{day:"numeric",month:"short",year:"numeric"})}function _({result:e,checkedAt:t,abn:s,declaredGst:a,className:l}){if(!e||!t)return null;let o=(0,n.jsxs)("span",{className:"text-muted-foreground",title:(0,h.KQ)(t),children:["Checked ",(0,h.BM)(t)]});if(!e.ok)return(0,n.jsx)("div",{className:(0,w.cn)("rounded-lg border border-warning-border bg-warning-surface px-3 py-2 text-xs",l),children:(0,n.jsxs)("p",{className:"flex items-start gap-2",children:[(0,n.jsx)(r.A,{className:"mt-0.5 size-3.5 shrink-0 text-warning","aria-hidden":!0}),(0,n.jsxs)("span",{children:[(0,n.jsx)("span",{className:"font-medium",children:"not_found"===e.reason?"The Australian Business Register holds no record of this ABN.":"The Australian Business Register couldn't be asked."})," ",o]})]})});let d=!!s&&e.abn!==s,c="boolean"==typeof a&&a!==e.gstRegistered,m=[e.state,e.postcode].filter(
1Boolean).join(" ");return(0,n.jsxs)("div",{className:(0,w.cn)("rounded-lg border bg-muted/30 px-3 py-2.5 text-xs",l),children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-x-2 gap-y-1",children:[(0,n.jsx)(i.A,{className:"size-3.5 shrink-0 text-muted-foreground","aria-hidden":!0}),(0,n.jsx)("span",{className:"font-medium",children:"Australian Business Register"}),(0,n.jsx)(p.E,{variant:"active"===e.status?"success":"destructive",children:"active"===e.status?"Active":"Cancelled"}),(0,n.jsx)(p.E,{variant:e.gstRegistered?"outline":"muted",children:e.gstRegistered?`GST from ${v(e.gstFrom)}`:"Not registered for GST"}),o]}),(0,n.jsxs)("p",{className:"mt-1.5 break-words text-sm",children:[e.entityName??"No name on the register",e.entityType&&(0,n.jsxs)("span",{className:"text-muted-foreground",children:[" \xb7 ",e.entityType]}),m&&(0,n.jsxs)("span",{className:"text-muted-foreground",children:[" \xb7 ",m]})]}),(d||c||"active"!==e.status)&&(0,n.jsxs)("ul",{className:"mt-2 space-y-1 text-warning",children:[d&&(0,n.jsxs)("li",{children:["This answer is for ",(0,f.PT)(e.abn),", not the ABN on file now. Check again."]}),"active"!==e.status&&(0,n.jsx)("li",{children:"The ABN is cancelled. A partner needs an active ABN to be paid as a contractor."}),c&&(0,n.jsxs)("li",{children:["They said they ",a?"are":"aren't"," registered for GST; the register says they ",e.gstRegistered?"are":"aren't",".",a?" GST is only paid on a confirmed registration, and the register doesn't confirm this one.":" No GST is paid while their profile says not registered: change it in Edit if the register is right."]})]})]})}function N(e){if(null===e.gst_registered||void 0===e.gst_registered)return"â";if(!(0,b.MY)(e))return e.gst_registered?"Yes":"No";switch((0,b.j7)(e)){case"confirmed":return"Yes, confirmed";case"unconfirmed":return"Yes, NOT confirmed";default:return"No"}}let k={abr:"confirmed by the register",admin:"confirmed by an admin",legacy:"confirmed when they were approved, before the register had to back it,"};function S({partner:e,override:t,onChanged:s,className:i}){let d=(0,a.useId)(),[m,h]=(0,a.useState)(null),[p,f]=(0,a.useState)(null),[j,y]=(0,a.useState)(""),[_,N]=(0,a.useState)(!1),[$,T]=(0,a.useState)(null),C=(0,a.useRef)(null),A=(0,b.MY)(e),B=m??t??{registered:e.gst_registered??null,applies:(0,b.Bt)(e),confirmed_at:e.gst_confirmed_at??null,source:e.gst_confirmed_source??null},R=A?(0,b.j7)({gst_registered:B.registered,gst_confirmed_at:B.confirmed_at}):(0,b.j7)({gst_registered:B.registered});async function D(){if(p&&!_&&j.trim()){N(!0),T(null),C.current??=crypto.randomUUID();try{let t=await (0,g.nr)(`/api/admin/partners/${e.id}/gst-confirm`,{method:"POST",body:JSON.stringify({confirmed:"confirm"===p,note:j.trim(),request_id:C.current,...e.abn?{abn:e.abn}:{}})});C.current=null,h(t.gst),c.oR.success("confirm"===p?"GST registration confirmed. GST is added to the lines created from now on.":"Confirmation removed. They are paid without GST until it is confirmed again."),f(null),y(""),await s?.()}catch(e){e instanceof g.E6&&(C.current=null),T(e instanceof g.E6&&"migration_required"===e.code?"Confirming a GST registration needs the latest database update (0079_partner_details_emails.sql).":e.message||"That didn't go through. Nothing was changed.")}finally{N(!1)}}}if("unanswered"===R)return(0,n.jsx)("p",{className:(0,w.cn)("text-xs text-muted-foreground",i),children:"GST: they haven't said whether they are registered."});if("not_registered"===R)return(0,n.jsx)("p",{className:(0,w.cn)("text-xs text-muted-foreground",i),children:"GST: not registered. Paid without GST."});let G="confirmed"===R;return(0,n.jsxs)("div",{className:(0,w.cn)("rounded-lg border px-3 py-2.5 text-xs",G?"bg-muted/30":"border-warning-border bg-warning-surface",i),children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-x-3 gap-y-2",children:[(0,n.jsxs)("p",{className:"flex min-w-0 items-start gap-2",children:[G?(0,n.jsx)(l.A,{className:"mt-0.5 size-3.5 shrink-0 text-muted-foreground","aria-hidden":!0}):(0,n.jsx)(r.A,{className:"mt-0.5 size-3.5 shrink-0 text-warning","aria-hidden":!0}),(0,n.jsx)("span",{children:A?G?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("span",{className:"font-medium",children:["GST: registered, ",B.source?k[B.source]:"confirmed",B.confirmed_at?` on ${v(B.confirmed_at)}`:"","."]})," ","10% GST is added to what they are paid."]}):(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("span",{className:"font-medium",children:"GST: registered, NOT confirmed."})," Paid without GST until confirmed. Check the ABN with the register, or confirm it by hand if you have checked another way."]}):(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("span",{className:"font-medium",children:"GST: registered."})," Paid with GST on their own word. Confirming a registration needs the latest database update (",(0,n.jsx)("code",{className:"font-mono",children:"00
179_partner_details_emails.sql"}),")."]})})]}),A&&!p&&(0,n.jsx)(x.$,{type:"button",size:"sm",variant:"outline",onClick:()=>f(G?"remove":"confirm"),children:G?"Remove confirmation":"Confirm GST"})]}),p&&(0,n.jsxs)("div",{className:"mt-3 space-y-2 border-t pt-3",children:[(0,n.jsx)("label",{htmlFor:d,className:"block text-xs font-medium",children:"confirm"===p?"How do you know they are registered for GST?":"Why is the confirmation being removed?"}),(0,n.jsx)("textarea",{id:d,className:(0,w.cn)(u.pc,"mt-0 bg-background"),rows:2,maxLength:1e3,value:j,onChange:e=>{y(e.target.value),T(null)},disabled:_,placeholder:"confirm"===p?"Looked up on abr.business.gov.au today: active, registered for GST":"The register shows the registration was cancelled",autoFocus:!0}),(0,n.jsx)("p",{className:"text-muted-foreground",children:"confirm"===p?"Kept in the audit log. GST is added to lines created from now on; lines already on their ledger donât change.":"Kept in the audit log. New lines carry no GST; lines already on their ledger donât change."}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsxs)(x.$,{type:"button",size:"sm",onClick:()=>void D(),disabled:_||!j.trim(),children:[_&&(0,n.jsx)(o.A,{className:"animate-spin"}),"confirm"===p?"Confirm GST registration":"Remove confirmation"]}),(0,n.jsx)(x.$,{type:"button",size:"sm",variant:"ghost",onClick:()=>{f(null),T(null)},disabled:_,children:"Cancel"}),$&&(0,n.jsx)("span",{role:"alert",className:"text-destructive",children:$})]})]})]})}function $({partner:e,onChecked:t,available:s=!0,showGst:r=!0,className:i}){let[l,u]=(0,a.useState)(!1),[h,p]=(0,a.useState)(!1),[f,j]=(0,a.useState)(null),[y,v]=(0,a.useState)(null),N=(0,a.useRef)(null),k=y?.abr_result??e.abr_result,T=y?.abr_checked_at??e.abr_checked_at,C=!!(k&&T),A=y&&e.abr_checked_at&&Date.parse(e.abr_checked_at)>=Date.parse(y.abr_checked_at)?null:y?.gst??null;async function B(){if(!l){u(!0),j(null),N.current??=crypto.randomUUID();try{let s=await (0,g.nr)(`/api/admin/partners/${e.id}/abn-check`,{method:"POST",body:JSON.stringify({request_id:N.current})});N.current=null,v(s);let n=(0,b.Bt)(e),a=s.gst?s.gst.applies:n;c.oR.success(s.abr_result.ok?a&&!n?"The register's answer is saved, and it confirms their GST registration.":"The register's answer is saved.":"The register holds no record of that ABN."),n&&!a&&c.oR.warning("The register doesn't back their GST registration, so the confirmation was removed. They are paid without GST."),await t?.()}catch(e){e instanceof g.E6&&"migration_required"===e.code?p(!0):j(e.message||"The check didn't run. Nothing was changed.")}finally{u(!1)}}}return e.abn?(0,n.jsxs)("div",{className:(0,w.cn)("space-y-2",i),children:[r&&(0,n.jsx)(S,{partner:e,override:A,onChanged:t},`${e.gst_confirmed_at??""}|${String(e.gst_registered)}`),(0,n.jsx)(_,{result:k,checkedAt:T,abn:e.abn,declaredGst:e.gst_registered}),h?(0,n.jsx)(m.A,{what:"Checking an ABN with the register",compact:!0}):s?(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-1.5",children:[(0,n.jsxs)(x.$,{type:"button",size:"sm",variant:"outline",onClick:()=>void B(),disabled:l,children:[l?(0,n.jsx)(o.A,{className:"animate-spin"}):(0,n.jsx)(d,{}),C?"Check again":"Check with the ABR"]}),!C&&!f&&(0,n.jsx)("span",{className:"text-xs text-muted-foreground",children:"Looks up who the ABN is registered to and whether it is registered for GST."}),f&&(0,n.jsx)("span",{role:"alert",className:"text-xs text-destructive",children:f})]}):(0,n.jsxs)("p",{className:"text-xs text-muted-foreground",children:["The ABN lookup isn't set up here, so this ABN can't be checked from the console. Look it up at"," ",(0,n.jsx)("a",{href:"https://abr.business.gov.au",target:"_blank",rel:"noreferrer",className:"underline underline-offset-2 hover:text-foreground",children:"abr.business.gov.au"})," ","to see who it is registered to and whether it is registered for GST."]})]}):null}},53487:(e,t,s)=>{s.d(t,{Eg:()=>k,WT:()=>v,_W:()=>_,aB:()=>b,mz:()=>N});var n=s(95155),a=s(12115),r=s(20986),i=s(41585),l=s(66609),o=s(83765),d=s(61732),c=s(13909),m=s(45160),u=s(89239),h=s(27529),p=s(77977),x=s(40980);let g={commission:"Commission",bonus:"Bonus",adjustment:"Adjustment",clawback:"Clawback"};function f(e,t){switch(t){case"onboarding":return"payout setup not finished";
1case"suspended":return"partner suspended";case"payout_hold":return"payouts on hold for this partner";case"platform_balance":return e.next_attempt_at?`Stripe balance short, retrying at ${(0,d.KQ)(e.next_attempt_at)}`:"Stripe balance short";case"source_cap":return"over what the client's charge can cover";case"waiting_period":return e.next_attempt_at?`waiting period, can be sent from ${(0,d.KQ)(e.next_attempt_at)}`:"waiting period";case"review":return"data"===e.review_state?"charge under review because its details need checking":"charge under review because of a refund or dispute";default:return String(t).replace(/_/g," ")}}function b(e){let t=e.hold??(e.review_state?"review":null);switch(e.state){case"pending_approval":return{label:"Awaiting approval",variant:"warning",note:t?`Then held: ${f(e,t)}`:null,held:!1,failed:!1};case"payable":if("waiting_period"===t)return{label:"Waiting period",variant:"outline",note:e.next_attempt_at?`Can be sent from ${(0,d.KQ)(e.next_attempt_at)}`:null,held:!1,failed:!1};if(t)return{label:`Held: ${f(e,t)}`,variant:"destructive",note:null,held:!0,failed:!1};if(e.last_error)return{label:"Last attempt failed",variant:"destructive",note:e.next_attempt_at&&Date.parse(e.next_attempt_at)>Date.now()?`Retrying at ${(0,d.KQ)(e.next_attempt_at)}`:"Tried again on the next pass",held:!1,failed:!0};return{label:"Ready",variant:"outline",note:e.next_attempt_at&&Date.parse(e.next_attempt_at)>Date.now()?`Next attempt ${(0,d.KQ)(e.next_attempt_at)}`:null,held:!1,failed:!1};case"transferring":{let t=e.attempted_at?`Started ${(0,d.KQ)(e.attempted_at)}`:null;if(e.attempted_at&&Date.now()-Date.parse(e.attempted_at)>9e5)return{label:"Sending for over 15 minutes",variant:"warning",note:t?`${t}. Check this transfer in Stripe if it doesn't settle.`:null,held:!1,failed:!1};return{label:"Sending",variant:"outline",note:t,held:!1,failed:!1}}case"transferred":{let t=e.transferred_at?(0,d.KQ)(e.transferred_at):null,s=e.reversed_cents??0;if(s>0){let n=null!=e.transfer_cents&&s>=e.transfer_cents;return{label:n?"Sent, then pulled back":`Sent, ${(0,c.Bs)(s)} pulled back`,variant:"warning",note:[t?`Sent ${t}`:null,n?`${(0,c.Bs)(s)} taken back from the partner`:null].filter(Boolean).join(" \xb7 ")||null,held:!1,failed:!1}}return{label:"Sent",variant:"success",note:t,held:!1,failed:!1}}case"void":return{label:"Cancelled",variant:"muted",note:e.void_reason,held:!1,failed:!1};default:return{label:String(e.state).replace(/_/g," "),variant:"muted",note:null,held:!1,failed:!1}}}let w="lg:grid-cols-[minmax(180px,1.6fr)_minmax(130px,1fr)_130px_minmax(200px,1.5fr)_84px]";function j(){return(0,n.jsxs)("div",{className:(0,x.cn)("hidden gap-3 border-b bg-muted/40 px-5 py-2 text-xs font-medium text-muted-foreground lg:grid",w),children:[(0,n.jsx)("span",{children:"Client"}),(0,n.jsx)("span",{children:"For"}),(0,n.jsx)("span",{className:"text-right",children:"Amount"}),(0,n.jsx)("span",{children:"Status"}),(0,n.jsx)("span",{})]})}function y({line:e,onChanged:t}){let s,[i,o]=(0,a.useState)(!1),f=b(e),j="payable"===e.state&&!!(e.hold||e.next_attempt_at);async function _(){o(!0);try{await (0,h.nr)(`/api/admin/partners/ledger/${e.id}/retry`,{method:"POST",body:JSON.stringify({request_id:crypto.randomUUID()})}),l.oR.success("Back in the queue. It is tried again on the next pass."),await t()}catch(e){l.oR.error(e.message)}finally{o(!1)}}return(0,n.jsxs)("li",{className:(0,x.cn)("grid grid-cols-2 gap-x-3 gap-y-1.5 px-5 py-3 text-sm lg:items-center",w),children:[(0,n.jsxs)("span",{className:"col-span-2 min-w-0 lg:col-span-1",children:[(0,n.jsx)("span",{className:"block truncate font-medium",children:e.client_name}),(0,n.jsxs)("span",{className:"block truncate text-xs text-muted-foreground",children:[e.plan_name??"No plan"," \xb7 ",(0,d.KQ)(e.created_at)]})]}),(0,n.jsx)("span",{className:"min-w-0 truncate",children:(s=[g[e.kind]??e.kind],"commission"===e.kind&&null!=e.rate_bps&&s.push(`${e.rate_bps/100}%`),e.role&&"full_cycle"!==e.role&&s.push(p.n[e.role]??e.role),s.join(" \xb7 "))}),(0,n.jsxs)("span",{className:"text-right tabular-nums",children:[(0,n.jsx)("span",{className:(0,x.cn)("block","void"===e.state&&"text-muted-foreground line-through"),children:(0,c.Bs)(e.amount_cents)}),(0,n.jsx)("span",{className:"block text-xs text-muted-foreground",children:e.gst_cents?`+ ${(0,c.Bs)(e.gst_cents)} GST`:"No GST"})]}),(0,n.jsxs)("span",{className:"col-span-2 min-w-0 lg:col-span-1",children:[(0,n.jsx)(m.E,{variant:f.variant,className:"h-auto max-w-full whitespace-normal text-left",children:f.label}),f.note&&(0,n.jsx)("span",{className:"mt-0.5 block text-xs text-muted-foreground",children:f.note}),(0,n.jsx)(v,{line:e,status:f})]}),(0,n.jsx)("span",{className:"col-span-2 lg:col-span-1 lg:text-right",children:j&&(0,n.jsxs)(u.$,{size:"sm",variant:"outline",onClick:_,disabled:i,children:[(0,n.jsx)(r.A,{className:(0,x.cn)(i&&"animate-spin")}),"Retry"]})})]})}function v({line:e,status:t}){return e.last_error&&(t.held||t.failed)?(0,n.jsxs)("span",{className:"mt-0.5 block break-words text-xs text-destructive",children:["Stripe said: ",e.last_error]}):null}function _(){return(0,n.jsxs)("div",{className:"mb-4 flex items-start gap-3 rounded-xl border border-warning-border bg-warning-surface px-4 py-3 text-sm",children:[(0,n.jsx)(i.A,{className:"mt-0.5 size-4 shrink-0 text-warning","aria-hidden":!0}),(0,n.jsxs)("p",{children:["The partner ledger isn't in this database yet. Apply"," ",(0,n.jsx)("code",{className:"font-mono text-xs",children:"supabase/migrations/0075_partner_ledger.sql"})," and reload. Until then no commission is recorded and nothing can be paid."]})]})}function N({what:e,onRetry:t}){return(0,n.jsxs)("div",{role:"alert",className:"flex flex-col items-start gap-3 px-5 py-8 sm:flex-row sm:items-center sm:justify-between",children:[(0,n.jsxs)("div",{className:"flex items-start gap-3",children:[(0,n.jsx)(i.A,{"aria-hidden":!0,
1className:"mt-0.5 size-4 shrink-0 text-warning"}),(0,n.jsxs)("div",{children:[(0,n.jsxs)("p",{className:"text-sm font-medium",children:["Couldn't load ",e]}),(0,n.jsx)("p",{className:"mt-0.5 text-sm text-muted-foreground",children:"Nothing was changed. Try again in a moment."})]})]}),(0,n.jsxs)(u.$,{type:"button",variant:"outline",size:"sm",onClick:t,children:[(0,n.jsx)(r.A,{"aria-hidden":!0}),"Try again"]})]})}function k({partnerId:e}){let[t,s]=(0,a.useState)(null),[r,i]=(0,a.useState)(!1),[m,u]=(0,a.useState)(1),p=(0,a.useCallback)(async()=>{i(!1);try{let t=new URLSearchParams({partner:e,page:String(m)});s(await (0,h.nr)(`/api/admin/partners/ledger?${t}`))}catch(e){i(!0),l.oR.error(`Couldn't load the ledger: ${e.message}`)}},[e,m]);(0,a.useEffect)(()=>{p()},[p]);let x=t?.totals;return(0,n.jsx)(d.Panel,{title:"Ledger",description:x?`Commission and bonuses owed to this partner, with GST. ${(0,c.Bs)(x.payable_cents)} ready to send \xb7 ${(0,c.Bs)(x.held_cents)} held${x.failed_cents?` \xb7 ${(0,c.Bs)(x.failed_cents)} failed its last attempt`:""} \xb7 ${(0,c.Bs)(x.pending_approval_cents)} awaiting approval \xb7 ${(0,c.Bs)(x.transferred_cents)} sent${x.reversed_cents?`, after ${(0,c.Bs)(x.reversed_cents)} pulled back`:""}.`:"Commission and bonuses owed to this partner, with GST.",flush:!0,children:t?.migrationRequired?(0,n.jsx)("div",{className:"border-t px-5 pt-4",children:(0,n.jsx)(_,{})}):!t&&r?(0,n.jsx)("div",{className:"border-t",children:(0,n.jsx)(N,{what:"this partner's ledger",onRetry:()=>void p()})}):t?t.rows.length?(0,n.jsxs)("div",{className:"border-t",children:[(0,n.jsx)(j,{}),(0,n.jsx)("ul",{className:"divide-y",children:t.rows.map(e=>(0,n.jsx)(y,{line:e,onChanged:p},e.id))}),t.total>t.pageSize&&(0,n.jsx)("div",{className:"border-t px-5 pb-3",children:(0,n.jsx)(o.is,{page:t.page,pageSize:t.pageSize,total:t.total,onPage:u})})]}):(0,n.jsx)("p",{className:"border-t px-5 py-10 text-center text-sm text-muted-foreground",children:"No lines yet. One appears here when a client attributed to this partner pays an invoice."}):(0,n.jsx)("div",{className:"space-y-2 border-t px-5 py-4",children:Array.from({length:3}).map((e,t)=>(0,n.jsx)("div",{className:"h-9 animate-pulse rounded bg-muted"},t))})})}},60529:(e,t,s)=>{s.d(t,{p:()=>i});var n=s(95155),a=s(12115),r=s(40980);let i=a.forwardRef(({className:e,type:t,...s},a)=>(0,n.jsx)("input",{type:t,ref:a,className:(0,r.cn)("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",e),...s}));i.displayName="Input"},61732:(e,t,s)=>{s.d(t,{At:()=>g,BI:()=>p,BM:()=>u,KQ:()=>h,Panel:()=>f,Wh:()=>m,Y2:()=>x});var n=s(95155),a=s(98500),r=s.n(a),i=s(21362),l=s(45160),o=s(13364),d=s(40980);let c={running:"Running",sleeping:"Asleep",stopped:"Stopped",paused:"Paused for credit",provisioning:"Provisioning",starting:"Starting",restarting:"Restarting",updating:"Updating",failed:"Failed",error:"Error",deleting:"Deleting"};function m({status:e}){let t=e??"unknown",s="paused"===t?"destructive":(0,o.iS)(t);return(0,n.jsxs)(l.E,{variant:s,className:"gap-1.5",children:[(0,n.jsx)("span",{"aria-hidden":!0,className:(0,d.cn)("size-1.5 rounded-full","success"===s&&"bg-emerald-500","warning"===s&&"bg-amber-500","destructive"===s&&"bg-current","muted"===s&&"bg-muted-foreground/60")}),c[t]??t.replace(/_/g," ")]})}function u(e){if(!e)return"â";let t=Date.now()-new Date(e).getTime(),s=Math.abs(t)/1e3,n=s<60?"just now":s<3600?`${Math.floor(s/60)}m`:s<86400?`${Math.floor(s/3600)}h`:s<2592e3?`${Math.floor(s/86400)}d`:null;return"just now"===n?n:n?t<0?`in ${n}`:`${n} ago`:new Date(e).toLocaleDateString("en-AU",{day:"numeric",month:"short",year:"numeric"})}function h(e){return e?new Date(e).toLocaleString("en-AU",{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"â"}function p({items:e}){return(0,n.jsx)("nav",{"aria-label":"Breadcrumb",className:"mb-3 flex flex-wrap items-center gap-1 text-xs text-muted-foreground",children:e.map((e,t)=>(0,n.jsxs)("span",{className:"flex items-center gap-1",children:[t>0&&(0,n.jsx)(i.A,{className:"size-3","aria-hidden":!0}),e.href?(0,n.jsx)(r(),{href:e.href,className:"hover:text-foreground",children:e.label}):(0,n.jsx)("span",{className:"text-foreground",children:e.label})]},t))})}function x({tabs:e,value:t,onChange:s}){return(0,n.jsx)("div",{role:"tablist",className:"mb-6 flex gap-5 overflow-x-auto border-b [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",children:e.map(e=>{let a=e.value===t;return(0,n.jsxs)("button",{type:"button",role:"tab","aria-selected":a,onClick:()=>s(e.value),className:(0,d.cn)("-mb-px inline-flex shrink-0 items-center gap-1.5 border-b-2 pb-2.5 text-sm font-medium transition-colors",a?"border-foreground text-foreground":"border-transparent text-muted-foreground hover:text-foreground"),children:[e.label,void 0!==e.count&&(0,n.jsx)("span",{className:"text-xs tabular-nums text-muted-foreground",children:e.count})]},e.value)})})}function g({items:e,className:t}){return(0,n.jsx)("dl",{className:(0,d.cn)("grid gap-x-6 gap-y-3 sm:grid-cols-2 lg:grid-cols-3",t),children:e.map(e=>(0,n.jsxs)("div",{className:"min-w-0",children:[(0,n.jsx)("dt",{className:"text-xs text-muted-foreground",children:e.label}),(0,n.jsx)("dd",{className:(0,d.cn)("mt-0.5 truncate text-sm",e.mono&&"font-mono text-xs"),children:e.value})]},e.label))})}function f({title:e,description:t,action:s,children:a,className:r,flush:i}){return(0,n.jsxs)("section",{className:(0,d.cn)("min-w-0 overflow-hidden rounded-xl border bg-card",r),children:[(e||s)&&(0,n.jsxs)("header",{className:"flex items-start justify-between gap-3 px-5 pt-4",children:[(0,n.jsxs)("div",{className:"min-w-0",children:[e&&(0,n.jsx)("h2",{className:"text-sm font-semibold",children:e}),t&&(0,n.jsx)("p",{className:"mt-0.5 text-xs text-muted-foreground",children:t})]}),s&&(0,n.jsx)("div",{className:"flex shrink-0 items-center gap-2",children:s})]}),(0,n.jsx)("div",{className:(0,d.cn)(i?"mt-3":"p-5",e&&!i&&"pt-3"),children:a})]})}},80054:(e,t,s)=>{s.d(t,{H:()=>p});
1var n=s(95155),a=s(12115),r=s(6296),i=s(66609),l=s(48875),o=s(83765),d=s(89239),c=s(42763),m=s(27529),u=s(77977),h=s(40980);function p({partner:e,duplicateAbn:t,abrAvailable:s=!0,onOpenChange:r,onDone:i}){let[l,o]=(0,a.useState)(!1);return(0,n.jsx)(c.lG,{open:!!e,onOpenChange:e=>!l&&r(e),children:(0,n.jsx)(c.Cf,{className:"sm:max-w-lg",children:e&&(0,n.jsx)(x,{partner:e,duplicateAbn:t??[],abrAvailable:s,busy:l,setBusy:o,onClose:()=>r(!1),onDone:i},e.id)})})}function x({partner:e,duplicateAbn:t,abrAvailable:s,busy:p,setBusy:g,onClose:f,onDone:b}){let w=(0,o.M)(e),[j,y]=(0,a.useState)("approve"),[v,_]=(0,a.useState)(()=>e.handle??(0,u.zc)(e.legal_name??"")),[N,k]=(0,a.useState)(null),[S,$]=(0,a.useState)(e.role_type),[T,C]=(0,a.useState)("trial"),[A,B]=(0,a.useState)(""),R="approve"===j?null===(0,o.Iw)(v):A.trim().length>0;async function D(){if(R&&!p){g(!0);try{await (0,m.nr)(`/api/admin/partners/${e.id}/review`,{method:"POST",body:JSON.stringify({expected_updated_at:e.updated_at,..."approve"===j?{action:"approve",handle:v,role_type:S,stage:T,...A.trim()?{note:A.trim()}:{}}:{action:"reject",note:A.trim()}})}),i.oR.success("approve"===j?`${w} is approved. They'll get an email with their partner link.`:`${w}'s application is declined. They'll get an email that doesn't include your note.`),f(),await b()}catch(e){e instanceof m.E6&&"handle_taken"===e.code?k(e.message):e instanceof m.E6&&("partner_not_submitted"===e.code||"partner_changed"===e.code)?(i.oR.error(e.message),f(),await b()):i.oR.error(e.message)}finally{g(!1)}}}return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(c.c7,{children:[(0,n.jsxs)(c.L3,{children:["Review ",w]}),(0,n.jsx)(c.rr,{children:"approve"===j?"Approving opens the partner portal to them and makes their link live. They can be paid once they finish Stripe's payout setup.":"They are emailed that the application wasn't approved. No reason is given, and you can reopen it later."})]}),(0,n.jsx)("div",{className:"grid grid-cols-2 gap-1 rounded-lg border bg-muted/40 p-1",role:"tablist","aria-label":"Decision",children:["approve","reject"].map(e=>(0,n.jsx)("button",{type:"button",role:"tab","aria-selected":j===e,disabled:p,onClick:()=>y(e),className:(0,h.cn)("rounded-md px-3 py-1.5 text-sm font-medium transition-colors disabled:opacity-50",j===e?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground"),children:"approve"===e?"Approve":"Decline"},e))}),(0,n.jsxs)("form",{className:"space-y-5",onSubmit:e=>{e.preventDefault(),D()},children:["approve"===j&&(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(o.jT,{matches:t}),(0,l.JO)(e)?(0,n.jsx)(l.NY,{result:e.abr_result,checkedAt:e.abr_checked_at,abn:e.abn,declaredGst:e.gst_registered}):e.abn&&(0,n.jsxs)("p",{className:"rounded-lg border bg-muted/30 px-3 py-2 text-xs text-muted-foreground",children:["This ABN passed its checksum only and hasn't been checked with the Australian Business Register. Check the registered name before you approve.",s?void 0!==e.abr_checked_at&&" Close this and press âCheck with the ABRâ on the application to see who it is registered to.":" The ABN lookup isnât set up here: look it up at abr.business.gov.au."]}),(0,n.jsx)(l.Zr,{partner:e}),(0,n.jsx)(o.Jg,{value:v,onChange:e=>{_(e),k(null)},error:N,disabled:p,autoFocus:!0}),(0,n.jsxs)("div",{className:"grid gap-4 sm:grid-cols-2",children:[(0,n.jsxs)("label",{className:"block text-sm font-medium",children:["How they sell",(0,n.jsx)("select",{className:o.p5,value:S,onChange:e=>$(e.target.value),disabled:p,children:u.wb.map(e=>(0,n.jsx)("option",{value:e,children:u.n[e]},e))})]}),(0,n.jsxs)("label",{className:"block text-sm font-medium",children:["Stage",(0,n.jsx)("select",{className:o.p5,value:T,onChange:e=>C(e.target.value),disabled:p,children:u.Rc.map(e=>(0,n.jsx)("option",{value:e,children:u.J4[e]},e))})]})]}),(0,n.jsx)("p",{className:"-mt-2 text-xs text-muted-foreground",children:"How they sell decides what their link produces: a full-cycle partner's link makes a full-cycle deal, a setter's or a closer's makes a split deal with their side filled in."})]}),(0,n.jsxs)("label",{className:"block text-sm font-medium",children:["approve"===j?"Internal note":"Why it is declined"," ",(0,n.jsx)("span",{className:"font-normal text-muted-foreground",children:"approve"===j?"(optional)":"(required, internal)"}),(0,n.jsx)("textarea",{className:o.pc,value:A,onChange:e=>B(e.target.value),rows:3,maxLength:2e3,placeholder:"approve"===j?"e.g. Met on a call, referred by an existing partner":"e.g. ABN belongs to someone else, asked them to re-apply",disabled:p}),(0,n.jsx)("span",{className:"mt-1.5 block text-xs font-normal text-muted-foreground",children:"Kept on the partner's page and in the audit log. Never shown or sent to the applicant."})]}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(d.$,{type:"button",variant:"outline",onClick:f,disabled:p,children:"Cancel"}),(0,n.jsxs)(d.$,{type:"submit",variant:"reject"===j?"destructive":"default",disabled:p||!R,children:[p&&(0,n.jsx)(r.A,{className:"animate-spin"}),"approve"===j?"Approve":"Decline"]})]})]})]})}},80813:(e,t,s)=>{function n(e){return!!e&&Object.prototype.hasOwnProperty.call(e,"gst_confirmed_at")}function a(e){return!!e&&!0===e.gst_registered&&(!n(e)||"string"==typeof e.gst_confirmed_at&&e.gst_confirmed_at.length>0)}function r(e){return e&&null!==e.gst_registered&&void 0!==e.gst_registered?!0!==e.gst_registered?"not_registered":a(e)?"confirmed":"unconfirmed":"unanswered"}s.d(t,{Bt:()=>a,MY:()=>n,j7:()=>r})},83740:(e,t,s)=>{s.d(t,{A:()=>v,z:()=>k});var n=s(95155),a=s(12115),r=s(41585);let i=(0,s(78340).A)("CircleArrowUp",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m16 12-4-4-4 4",key:"177agl"}],["path",{d:"M12 16V8",key:"1sbj14"}]]);var l=s(6296),o=s(94514),d=s(55711),c=s(66609),m=s(87757),u=s(53487),h=s(83765),p=s(61732),x=s(75230),g=s(45160),f=s(89239),b=s(60529),w=s(27529),j=s(77977),y=s(40980);function v({what:e,compact:t,className:s}){return t?(0,n.jsxs)("p",{className:(0,y.cn)("text-xs text-muted-foreground",s),children:[e," needs the latest database update (",(0,n.jsx)("code",{className:"font-mono",children:"00
177_partner_gate.sql"}),")."]}):(0,n.jsxs)("div",{className:(0,y.cn)("flex items-start gap-3 rounded-xl border border-warning-border bg-warning-surface px-4 py-3 text-sm",s),children:[(0,n.jsx)(r.A,{className:"mt-0.5 size-4 shrink-0 text-warning","aria-hidden":!0}),(0,n.jsxs)("p",{children:[e," isn't available in this database yet. Apply"," ",(0,n.jsx)("code",{className:"font-mono text-xs",children:"supabase/migrations/0077_partner_gate.sql"})," and reload. Everything else on this page works as before."]})]})}function _(e){let t=e?/^(\d{4})-(\d{2})-(\d{2})/.exec(e):null;return t?new Date(Number(t[1]),Number(t[2])-1,Number(t[3])).toLocaleDateString("en-AU",{weekday:"short",day:"numeric",month:"short",year:"numeric"}):e??"â"}function N(e){let t=e?/^(\d{4})-(\d{2})-(\d{2})/.exec(e):null;return t?new Date(Number(t[1]),Number(t[2])-1,Number(t[3])).toLocaleDateString("en-AU",{day:"numeric",month:"short"}):""}function k({partner:e,onChanged:t}){let{data:s,failed:r,migrationRequired:l,reload:o}=(0,m.aV)(`/api/admin/partners/${e.id}/demos`,"the demos"),[d,b]=(0,a.useState)(!1),[y,C]=(0,a.useState)(null),[A,B]=(0,a.useState)(!1),R=s?.gate??null,D=s?.demos??[],G="trial"===e.stage,O="approved"===e.status||"suspended"===e.status,M=(0,h.M)(e),P=A?D:D.slice(0,8);async function U(){await (0,w.nr)(`/api/admin/partners/${e.id}`,{method:"PATCH",body:JSON.stringify({stage:"full"})}),c.oR.success(`${M} is now a full partner.`),await t()}async function z(){y&&(await (0,w.nr)(`/api/admin/partners/${e.id}/demos/${y.demo.id}/void`,{method:"POST",body:JSON.stringify({request_id:y.requestId})}),c.oR.success("Demo voided. It no longer counts."),await o())}return(0,n.jsxs)(p.Panel,{title:"Trial gate",description:`${j.NW.demos} demos held inside any ${j.NW.days} days in a row, or a first paying client. An admin logs the demos here. Meeting the gate promotes nobody: you do.`,action:G?(0,n.jsxs)(f.$,{size:"sm",variant:R?.met?"default":"outline",onClick:()=>b(!0),children:[(0,n.jsx)(i,{}),"Promote to full partner"]}):(0,n.jsx)(g.E,{variant:"success",children:"Full partner"}),flush:!0,children:[l?(0,n.jsxs)("div",{className:"border-t px-5 py-4",children:[(0,n.jsx)(v,{what:"Logging demos and trial progress"}),G&&(0,n.jsx)("p",{className:"mt-3 text-xs text-muted-foreground",children:"You can still promote this partner: their stage doesn't depend on it."})]}):!s&&r?(0,n.jsx)("div",{className:"border-t",children:(0,n.jsx)(u.mz,{what:"this partner's demos",onRetry:()=>void o()})}):s?(0,n.jsxs)(n.Fragment,{children:[R&&(0,n.jsx)(S,{gate:R,onTrial:G}),O?(0,n.jsx)($,{partnerId:e.id,onLogged:o}):(0,n.jsx)("p",{className:"border-t px-5 py-3 text-xs text-muted-foreground",children:"Demos are logged for an approved partner."}),D.length?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("ul",{className:"divide-y border-t",children:P.map(e=>(0,n.jsx)(T,{demo:e,onVoid:()=>C({demo:e,requestId:crypto.randomUUID()})},e.id))}),D.length>8&&(0,n.jsx)("div",{className:"border-t px-5 py-2",children:(0,n.jsx)("button",{type:"button",className:"text-xs font-medium text-muted-foreground underline-offset-2 hover:text-foreground hover:underline",onClick:()=>B(e=>!e),"aria-expanded":A,children:A?"Show fewer":`Show all ${D.length} demos`})})]}):(0,n.jsx)("p",{className:"border-t px-5 py-10 text-center text-sm text-muted-foreground",children:"No demos logged yet. Add each one after it is held, and the progress above counts them."})]}):(0,n.jsx)("div",{className:"border-t",children:(0,n.jsx)(m._N,{rows:3})}),(0,n.jsx)(x.T,{open:d,onOpenChange:b,title:`Promote ${M} to full partner?`,description:`${R?R.has_paying_client&&R.best_window_count>=R.demos_needed?`The gate is met twice over: ${R.best_window_count} demos inside ${R.days} days, and a paying client.`:R.has_paying_client?"The gate is met: they have a paying client.":R.met?`The gate is met: ${R.best_window_count} demos between ${N(R.best_window_start)} and ${N(R.best_window_end)}.`:`The gate isn't met yet: ${R.best_window_count} of ${R.demos_needed} demos in their best ${R.days} days, and no paying client.`:"Trial progress isn't available in this database yet, so check the gate yourself before you decide."} Promoting moves them off the trial stage now. Their clients, their rates on lines already recorded and anything they are owed stay as they are, and they aren't emailed, so let them know.`,confirmText:"Promote",onConfirm:U}),(0,n.jsx)(x.T,{open:!!y,onOpenChange:e=>!e&&C(null),title:"Void this demo?",description:y?`${y.demo.prospect_name}, ${_(y.demo.held_on)}. It stays on file, marked as voided, and stops counting towards the gate. This can't be und
1one: log it again if it was real.`:void 0,confirmText:"Void demo",destructive:!0,onConfirm:z})]})}function S({gate:e,onTrial:t}){let s=Math.min(e.best_window_count,e.demos_needed),a=e.best_window_count>=e.demos_needed;return(0,n.jsxs)("div",{className:"border-t px-5 py-4",children:[(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-1.5",children:[(0,n.jsxs)("p",{className:"text-sm",children:[(0,n.jsxs)("span",{className:"font-semibold tabular-nums",children:[e.best_window_count," of ",e.demos_needed]})," ","in the best ",e.days," days",(0,n.jsxs)("span",{className:"text-muted-foreground",children:[" ","\xb7 ",(0,n.jsx)("span",{className:"tabular-nums",children:e.current_window_count})," in the last ",e.days," days"]})]}),(0,n.jsx)(g.E,{variant:e.met?"success":"muted",children:e.met?"Gate met":"Not met yet"}),e.has_paying_client&&(0,n.jsx)(g.E,{variant:"outline",children:"Has a paying client"})]}),(0,n.jsx)("div",{className:"mt-3 flex max-w-sm gap-1",role:"img","aria-label":`${e.best_window_count} of ${e.demos_needed} demos in the best ${e.days} days`,children:Array.from({length:e.demos_needed}).map((e,t)=>(0,n.jsx)("span",{className:(0,y.cn)("h-1.5 flex-1 rounded-full transition-colors duration-200",t<s?a?"bg-emerald-500 dark:bg-emerald-400":"bg-foreground":"bg-muted")},t))}),(0,n.jsxs)("p",{className:"mt-2.5 text-xs text-muted-foreground",children:[e.best_window_count>0&&(0,n.jsxs)(n.Fragment,{children:["Best run: ",N(e.best_window_start),e.best_window_end&&e.best_window_end!==e.best_window_start?` to ${N(e.best_window_end)}`:"","."," "]}),e.demos_total," demo",1===e.demos_total?"":"s"," held in all.",e.met&&t&&" Ready to promote when you are."]})]})}function $({partnerId:e,onLogged:t}){let s=(0,m.PE)(),[r,i]=(0,a.useState)(s),[d,u]=(0,a.useState)(""),[h,p]=(0,a.useState)(""),[x,g]=(0,a.useState)(!1),[j,y]=(0,a.useState)(null),v=(0,a.useRef)(null),_=(0,a.useRef)(null),N=!!r&&r<=s&&d.trim().length>0;async function k(){if(N&&!x){g(!0),y(null),v.current??=crypto.randomUUID();try{await (0,w.nr)(`/api/admin/partners/${e}/demos`,{method:"POST",body:JSON.stringify({held_on:r,prospect_name:d.trim(),note:h.trim()||void 0,request_id:v.current})}),v.current=null,u(""),p(""),c.oR.success("Demo logged."),await t(),_.current?.focus()}catch(e){y(e.message||"That didn't save. Nothing was logged.")}finally{g(!1)}}}function S(e){return t=>{v.current=null,e(t)}}return(0,n.jsxs)("form",{className:"space-y-3 border-t bg-muted/20 px-5 py-4",onSubmit:e=>{e.preventDefault(),k()},children:[(0,n.jsxs)("div",{className:"grid gap-3 sm:grid-cols-[150px_minmax(0,1fr)] lg:grid-cols-[150px_minmax(0,1fr)_minmax(0,1.4fr)_auto] lg:items-end",children:[(0,n.jsxs)("label",{className:"block text-xs font-medium text-muted-foreground",children:["Held on",(0,n.jsx)(b.p,{type:"date",className:"mt-1 text-foreground",value:r,max:s,onChange:e=>S(i)(e.target.value),disabled:x,required:!0})]}),(0,n.jsxs)("label",{className:"block text-xs font-medium text-muted-foreground",children:["Prospect",(0,n.jsx)(b.p,{ref:_,className:"mt-1 text-foreground",value:d,onChange:e=>S(u)(e.target.value),maxLength:200,placeholder:"Business or person the demo was with",disabled:x})]}),(0,n.jsxs)("label",{className:"block text-xs font-medium text-muted-foreground sm:col-span-2 lg:col-span-1",children:["Note ",(0,n.jsx)("span",{className:"font-normal",children:"(optional)"}),(0,n.jsx)(b.p,{className:"mt-1 text-foreground",value:h,onChange:e=>S(p)(e.target.value),maxLength:1e3,placeholder:"How it went, who confirmed it",disabled:x})]}),(0,n.jsxs)(f.$,{type:"submit",size:"sm",className:"h-9 sm:col-span-2 sm:justify-self-start lg:col-span-1",disabled:x||!N,children:[x?(0,n.jsx)(l.A,{className:"animate-spin"}):(0,n.jsx)(o.A,{}),"Log demo"]})]}),(0,n.jsx)(m.lZ,{message:j})]})}function T({demo:e,onVoid:t}){let s=!!e.voided_at;return(0,n.jsxs)("li",{className:(0,y.cn)("flex flex-wrap items-start gap-x-4 gap-y-1 px-5 py-2.5 text-sm",s&&"text-muted-foreground"),children:[(0,n.jsx)("span",{className:"w-32 shrink-0 tabular-nums text-muted-foreground",children:_(e.held_on)}),(0,n.jsxs)("span",{className:"min-w-0 flex-1 basis-48",children:[(0,n.jsx)("span",{className:(0,y.cn)("block break-words font-medium",s&&"font-normal line-through"),children:e.prospect_name}),e.note&&(0,n.jsx)("span",{className:"block whitespace-pre-wrap break-words text-xs text-muted-foreground",children:e.note}),(0,n.jsxs)("span",{className:"block text-xs text-muted-foreground",title:(0,p.KQ)(e.created_at),children:["Logged by ",e.created_by,s?` \xb7 voided ${(0,p.KQ)(e.voided_at)}`:""]})]}),s?(0,n.jsx)(g.E,{variant:"muted",children:"Voided"}):(0,n.jsxs)(f.$,{type:"button",size:"sm",variant:"ghost",className:"h-7 px-2 text-xs text-muted-foreground hover:text-destructive","aria-label":`Void the demo with ${e.prospect_name} on ${_(e.held_on)}`,onClick:t,children:[(0,n.jsx)(d.A,{}),"Void"]})]})}},86846:(e,t,s)=>{s.d(t,{E:()=>r});var n=s(95155),a=s(40980);function r({className:e,...t}){return(0,n.jsx)("div",{className:(0,a.cn)("animate-pulse rounded-md bg-muted",e),...t})}}}]);
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.