PageSourceSearch

https://nwfloors.co.uk/assets/LeadSources-BszyOJBW.js

js nwfloors.co.uk collected 2026-10-08 17:36:56 UTC 23,167 bytes, 24 lines download raw bytes

1import{N as p,aZ as ce,r as x,u as k,j as a,I as f,B as h,b as ue}from"./index-D2rUcUpe.js";import{A as me}from"./AdminLayout-kkTddtqD.js";import{L as pe}from"./LeadSourceSelect-DKYTSQ9c.js";import{L as he,a as xe}from"./lostEnquiry-QmeJS1jh.js";import"./Helmet-D7MYuSoa.js";import"./log-out-Bsz1vMOl.js";import"./clipboard-list-COd5Au4H.js";import"./tag-s72l0Uly.js";import"./building-2-DpPm7j8z.js";import"./star-Dj3WDnZ7.js";import"./upload-B90ZdJYW.js";import"./share-2-BMS9JZH2.js";import"./calendar-days-BLrdobId.js";import"./wrench-CCizyO6G.js";const A=p.string().regex(/^\d{4}-\d{2}-\d{2}$/).refine(n=>{const l=new Date(`${n}T00:00:00Z`);return Number.isFinite(l.getTime())&&l.toISOString().slice(0,10)===n},"Invalid calendar date");p.object({sourceKey:p.string().trim().min(1).max(100),kind:p.enum(["period","job_fee"]),jobId:p.number().int().positive().nullable().default(null),amountPence:p.number().int().min(0).max(1e9),vatBasis:p.enum(["exclusive","inclusive","no_vat"]),vatRate:p.number().min(0).max(100).default(20),periodStart:A,periodEnd:A,description:p.string().trim().min(1).max(1e3),frequency:p.enum(["oneoff","monthly","quarterly","annual"]).default("oneoff")}).strict().superRefine((n,l)=>{n.periodEnd<n.periodStart&&l.addIssue({code:"custom",path:["periodEnd"],message:"End must follow start"}),n.kind==="period"&&n.jobId!==null&&l.addIssue({code:"custom",path:["jobId"],message:"Period spend cannot also be a job fee"}),n.kind==="job_fee"&&(!n.jobId||n.periodStart!==n.periodEnd)&&l.addIssue({code:"custom",path:["jobId"],message:"A job fee requires a job and a single recognition date"}),n.kind==="job_fee"&&n.frequency!=="oneoff"&&l.addIssue({code:"custom",path:["frequency"],message:"Job fees are one-off"}),n.frequency!=="oneoff"&&n.periodStart.slice(8)!=="01"&&l.addIssue({code:"custom",path:["periodStart"],message:"Recurring costs start on the first of a month"})});p.object({from:A,to:A}).refine(n=>n.to>=n.from&&(Date.parse(n.to)-Date.parse(n.from))/864e5<=1096,"Choose an ordered period of at most three years");function fe(n,l){return l?n.filter(N=>N.key===l):n}function be(n){const l=String(n??"");return`"${(typeof n=="string"&&/^[\s]*[=+\-@\t\r\n]/.test(l)?`'${l}`:l).replaceAll('"','""')}"`}const E=new Date().toISOString().slice(0,10),r=n=>n==null?"Not available":new Intl.NumberFormat("en-GB",{style:"currency",currency:"GBP"}).format(n),P={sourceKey:"",kind:"period",frequency:"oneoff",jobId:"",amount:"",vatBasis:"exclusive",vatRate:"20",periodStart:E,periodEnd:E,description:""};function Le(){var K,O,_,U,Q,H,G,M,z,J,W,Y,Z,X,ee,ae,se;const n=ce(),[l,N]=x.useState(""),[T,$]=x.useState(""),[b,R]=x.useState(!1),[t,m]=x.useState(P),[g,q]=x.useState(null),[j,ie]=x.useState(`${E.slice(0,7)}
1-01`),[v,oe]=x.useState(E),[S,ne]=x.useState(""),w=k({queryKey:["/api/admin/lead-sources"]}),I=k({queryKey:["/api/admin/lead-source-costs"]}),V=k({queryKey:["/api/admin/lead-source-fixed-costs"]}),B=k({queryKey:["/api/admin/lead-source-jobs"]}),F=k({queryKey:["/api/admin/lead-source-audit"]}),u=k({queryKey:[`/api/admin/lead-source-report?from=${j}&to=${v}`],enabled:!!j&&!!v});async function y(e,d,s){R(!0),$("");try{return await ue(e,{method:d,data:s}),await n.invalidateQueries({predicate:c=>String(c.queryKey[0]).includes("lead-source")||String(c.queryKey[0]).includes("job-sheet")}),!0}catch(c){return $(c instanceof Error?c.message:"Operation failed"),!1}finally{R(!1)}}const D=e=>{var d,s;return((s=(d=w.data)==null?void 0:d.find(c=>c.key===e))==null?void 0:s.name)??e},C=fe(((K=u.data)==null?void 0:K.rows)??[],S);function re(){if(!u.data)return;const e=["Source","Spend ex VAT","Leads created","Quoted lead cohort","Paid lead cohort","Paid conversion","Open","Lost","Cost per lead","Cost per quote","Cost per paid lead","Invoiced sales ex VAT (issue dates)","Booked sales","Booked value ex VAT","Average booked sale ex VAT","Average days to paid sale","Estimated profit after spend","Actual profit after spend"],d=C.map(i=>[i.name,i.spend,i.leads,i.quotedLeads,i.paidLeads,i.paidConversionRate,i.openLeads,i.lostLeads,i.costPerLead,i.costPerQuote,i.costPerPaidLead,i.invoicedSales,i.jobsWon,i.bookedValueExVat,i.averageBookedSaleExVat,i.timeToSaleDays,i.estimatedContribution,i.actualContribution]),s=["Source","Detail type","Reference","Date / coverage","Amount GBP","Description / outcome"],c=C.flatMap(i=>[...(i.leadDetails??[]).map(o=>[i.name,"lead",`${o.kind} #${o.id}`,String(o.createdAt).slice(0,10),"",`${o.status}; first paid ${o.firstPaidAt??"unavailable"}; quote IDs ${(o.quoteIds??[]).join(" ")}`]),...i.jobs.map(o=>[i.name,"booked sale",`${o.kind} #${o.id}`,"",o.bookedValueExVat,o.href]),...i.invoices.map(o=>[i.name,"invoice",o.reference??o.id,"",o.value,o.note??""]),...i.costs.map(o=>[i.name,"source cost",`#${o.id}`,`${o.periodStart} – ${o.periodEnd}`,o.amountPence/100,`${o.description}; ${o.frequency}; ${o.vatBasis}`]),...i.linkedFixedExpenses.map(o=>[i.name,"fixed expense",`#${o.id}`,`${o.effectiveFrom} – ${o.effectiveTo??"ongoing"}`,o.monthlyAmount,`${o.label}; monthly`]),...Object.entries(i.lossReasons??{}).map(([o,le])=>[i.name,"lost reason",o,"",le,"lead cohort count"]),[i.name,"lost reason","unrecorded","",i.unrecordedLossReasons??0,"lead cohort count"]]),de=[[`Source report ${j} to ${v}`,S||"All sources"],e,...d,[],s,...c].map(i=>i.map(be).join(",")).join(`\r
2`),te=URL.createObjectURL(new Blob(["\uFEFF",de],{type:"text/csv;charset=utf-8"})),L=document.createElement("a");L.href=te,L.download=`source-report-${j}-${v}.csv`,L.click(),setTimeout(()=>URL.revokeObjectURL(te),1e3)}return a.jsx(me,{children:a.jsxs("main",{className:"p-4 md:p-6 space-y-6 max-w-7xl mx-auto",children:[a.jsxs("header",{children:[a.jsx("h1",{className:"text-3xl font-semibold",children:"Lead sources"}),a.jsx("p",{className:"text-slate-600 mt-2",children:"Manage referral partners, record acquisition costs and compare commercial value."})]}),(T||w.isError||I.isError||F.isError||u.isError)&&a.jsx("p",{role:"alert",className:"border border-red-300 bg-red-50 p-3",children:T||"Could not load source data. Please reload or check the selected dates."}),a.jsxs("section",{className:"source-editor border rounded-lg p-4 space-y-3",children:[a.jsx("h2",{className:"text-xl font-semibold",children:"Source catalogue"}),a.jsx("p",{className:"text-sm text-slate-600",children:"Private staff catalogue. Public forms keep their existing categories. Archiving preserves history; renaming updates labels, not attribution keys."}),a.jsxs("form",{className:"flex gap-2",onSubmit:async e=>{e.preventDefault(),await y("/api/admin/lead-sources","POST",{name:l})&&N("")},children:[a.jsx(f,{"aria-label":"New source name",placeholder:"e.g. referral partner",value:l,maxLength:100,required:!0,onChange:e=>N(e.target.value)}),a.jsx(h,{disabled:b,children:"Add source"})]}),a.jsx("div",{className:"grid sm:grid-cols-2 lg:grid-cols-3 gap-2",children:(O=w.data)==null?void 0:O.map(e=>a.jsxs("div",{className:"border rounded p-3 flex flex-wrap gap-2 items-center",children:[a.jsxs("span",{className:"flex-1",children:[e.name,e.archived&&a.jsx("small",{className:"block",children:"Archived"})]}),a.jsx(h,{size:"sm",variant:"outline",disabled:b,onClick:()=>{const d=window.prompt("Source name",e.name);d!=null&&d.trim()&&y(`/api/admin/lead-sources/${encodeURIComponent(e.key)}`,"PATCH",{name:d})},children:"Rename"}),a.jsx(h,{size:"sm",variant:"outline",disabled:b,onClick:()=>
2{window.confirm(`${e.archived?"Restore":"Archive"} ${e.name}? Historical attribution remains unchanged.`)&&y(`/api/admin/lead-sources/${encodeURIComponent(e.key)}`,"PATCH",{archived:!e.archived})},children:e.archived?"Restore":"Archive"})]},e.key))})]}),a.jsxs("section",{className:"source-editor border rounded-lg p-4 space-y-3",children:[a.jsx("h2",{className:"text-xl font-semibold",children:g?"Edit acquisition cost":"Record acquisition cost"}),a.jsx("p",{className:"text-sm text-slate-600",children:"GBP. Enter an explicit £0 for a free source. No entry means not recorded. Link an existing marketing fixed expense below instead of entering it again here. These are scheduled allocations, not proof that a bill was paid. For a price change, close the old coverage and create a new entry; never overwrite its historical price."}),a.jsxs("form",{className:"grid sm:grid-cols-2 lg:grid-cols-3 gap-3",onSubmit:async e=>{if(e.preventDefault(),!t.sourceKey||t.amount.trim()===""||!Number.isFinite(Number(t.amount))){$("Choose a source and enter a GBP amount, including 0 if free.");return}const d={sourceKey:t.sourceKey,kind:t.kind,frequency:t.kind==="job_fee"?"oneoff":t.frequency,jobId:t.kind==="job_fee"?Number(t.jobId):null,amountPence:Math.round(Number(t.amount)*100),vatBasis:t.vatBasis,vatRate:Number(t.vatRate),periodStart:t.periodStart,periodEnd:t.kind==="job_fee"?t.periodStart:t.periodEnd,description:t.description};await y(`/api/admin/lead-source-costs${g?`/${g}`:""}`,g?"PATCH":"POST",d)&&(m(P),q(null))},children:[a.jsxs("label",{children:["Source",a.jsx(pe,{value:t.sourceKey,onChange:e=>m({...t,sourceKey:e??""})})]}),a.jsxs("label",{children:["Cost type",a.jsxs("select",{className:"border rounded p-2 w-full",value:t.kind,onChange:e=>m({...t,kind:e.target.value}),children:[a.jsx("option",{value:"period",children:"Period advertising / source spend"}),a.jsx("option",{value:"job_fee",children:"One job acquisition fee"})]})]}),t.kind==="period"&&a.jsxs("label",{children:["Frequency",a.jsxs("select",{className:"border rounded p-2 w-full",value:t.frequency,onChange:e=>m({...t,frequency:e.target.value}),children:[a.jsx("option",{value:"oneoff",children:"One-off / actual coverage total"}),a.jsx("option",{value:"monthly",children:"Monthly amount"}),a.jsx("option",{value:"quarterly",children:"Quarterly amount"}),a.jsx("option",{value:"annual",children:"Annual amount"})]})]}),t.kind==="job_fee"&&a.jsxs("label",{children:["Job",a.jsxs("select",{className:"border rounded p-2 w-full",required:!0,value:t.jobId,onChange:e=>m({...t,jobId:e.target.value}),children:[a.jsx("option",{value:"",children:"Choose a job assigned to this source"}),(_=B.data)==null?void 0:_.filter(e=>e.leadSource===t.sourceKey||String(e.id)===t.jobId).map(e=>a.jsxs("option",{value:e.id,children:[e.jobNumber||`Job sheet #${e.id}`," · quote #",e.quoteId]},e.id))]}),B.isError&&a.jsx("span",{role:"alert",children:"Could not load jobs."})]}),a.jsxs("label",{children:["Amount (£)",a.jsx(f,{type:"number",min:"0",step:".01",required:!0,value:t.amount,onChange:e=>m({...t,amount:e.target.value})})]}),a.jsxs("label",{children:["VAT basis",a.jsxs("select",{className:"border rounded p-2 w-full",value:t.vatBasis,onChange:e=>m({...t,vatBasis:e.target.value}),children:[a.jsx("option",{value:"exclusive",children:"Amount excludes VAT"}),a.jsx("option",{value:"inclusive",children:"Amount includes VAT"}),a.jsx("option",{value:"no_vat",children:"No VAT charged"})]})]}),t.vatBasis!=="no_vat"&&a.jsxs("label",{children:["VAT rate (%)",a.jsx(f,{type:"number",min:"0",max:"100",step:".01",required:!0,value:t.vatRate,onChange:e=>m({...t,vatRate:e.target.value})})]}),a.jsxs("label",{children:[t.kind==="job_fee"?"Fee recognition date":"Coverage start (recurring: first of month)",a.jsx(f,{type:"date",required:!0,value:t.periodStart,onChange:e=>m({...t,periodStart:e.target.value})})]}),t.kind==="period"&&a.jsxs("label",{children:["Period end",a.jsx(f,{type:"date",required:!0,min:t.periodStart,value:t.periodEnd,onChange:e=>m({...t,periodEnd:e.target.value})})]}),a.jsxs("label",{children:["Description / bill reference",a.jsx(f,{required:!0,maxLength:1e3,value:t.description,onChange:e=>m({...t,description:e.target.value})})]}),a.jsxs("div",{className:"flex items-end gap-2",children:[a.jsx(h,{disabled:b,children:g?"Save correction":"Add cost"}),g&&a.jsx(h,{type:"button",variant:"outline",onClick:()=>{q(null),m(P)},children:"Cancel edit"})]})]}),a.jsxs("details",{children:[a.jsxs("summary",{className:"cursor-pointer font-medium",children:["All cost records (",((U=I.data)==null?void 0:U.length)??0,")"]}),a.jsx("div",{className:"space-y-2 mt-3",children:(Q=I.data)==null?void 0:Q.map(e=>a.jsxs("div",{className:"border rounded p-3 flex flex-wrap gap-3 items-center",children:[a.jsxs("div",{className:"flex-1 min-w-48",children:[a.jsxs("strong",{children:[D(e.sourceKey)," · ",r(e.amountPence/100)," per ",e.frequency||"oneoff"]}),a.jsxs("p",{children:[e.kind==="job_fee"?`Job fee · sheet #${e.jobId}`:"Period spend"," · ",e.periodStart," – ",e.periodEnd," · VAT ",e.vatBasis]}),a.jsx("p",{children:e.description})]}),a.jsx(h,{variant:"outline",disabled:b,onClick:()=>{q(e.id),m({...e,amount:String(e.amountPence/100),vatRate:String(e.vatRate),jobId:e.jobId==null?"":String(e.jobId)})},children:"Edit"}),a.jsx(h,{variant:"outline",disabled:b,onClick:()=>{window.confirm("Delete this cost? Historical reports will be recalculated. The audit history is retained.")&&y(`/api/admin/lead-source-costs/${e.id}`,"DELETE")},children:"Delete"})]},e.id))})]}),a.jsx("h3",{className:"font-semibold",children:"Existing marketing fixed expenses — link, do not duplicate"}),V.isError&&a.jsx("p",{role:"alert",children:"Could not load fixed expenses."}),(H=V.data)==null?void 0:H.filter(e=>e.category==="marketing").map(e=>{var d;return a.jsxs("div",{className:"border rounded p-3 flex flex-wrap gap-3 items-center",children:[a.jsxs("span",{className:"flex-1",children:[e.label," · ",r(e.monthlyAmount),"/month · ",e.effectiveFrom," – ",e.effectiveTo||"ongoing"]}),a.jsxs("select",{"aria-label":`Source for ${e.label}`,className:"border rounded p-2",value:e.sourceKey||"",disabled:b,onChange:async s=>{await y(`/api/admin/lead-source-fixed-costs/${e.id}`,"PATCH",{sourceKey:s.target.value||null})},children:[a.jsx("option",{value:"",children:"Unassigned marketing expense"}),(d=w.data)==null?void 0:d.filter(s=>!s.archived||s.key===e.sourceKey).map(s=>a.jsx("option",{value:s.key,children:s.name},s.key))]})]},e.id)})]}),a.jsxs("section",{className:"source-report border rounded-lg p-4 space-y-4",children:[a.jsx("h2",{className:"text-xl font-semibold",children:"Source comparison"}),a.jsxs("div",{className:"flex flex-wrap gap-3",children:[a.jsxs("label",{children:["From",a.jsx(f,{type:"date",value:j,max:v,onChange:e=>ie(e.target.value)})]}),a.jsxs("label",{children:["To",a.jsx(f,{type:"date",value:v,min:j,onChange:e=>oe(e.target.value)})]}),a.jsxs("label",{children:["Source",a.jsxs("select",{"aria-label":"Filter report by source",className:"block border rounded p-2",value:S,onChange:e=>ne(e.target.value),children:[a.jsx("option",{value:"",children:"All sources"}),(G=u.data)==null?void 0:G.rows.map(e=>a.jsx("option",{value:e.key,children:e.name},e.key))]})]}),a.jsx(h,{type:"button",variant:"outline",disabled:!u.data,onClick:re,children:"Export CSV"}),a.jsx(h,{type:"button",variant:"outline",disabled:!u.data,onClick:()=>window.print(),children:"Print / Save as PDF"})]}),a.jsxs("p",{className:"text-sm",children:["Showing: ",S?D(S):"All sources"," · ",j," – ",v,". CSV and print use this same selection."]}),a.jsx("style",{children:`@page { size: A4 landscape; margin: 10mm; }
3         @media print {
4           nav, aside, footer, main > :not(.source-report), .source-audit, .source-report button,
5           .source-report input, .source-report select, .source-report label, .source-report .source-excluded {
6             display: none !important;
7           }
8           html, body, #root, main, .source-report {
9             width: 100% !important; max-width: none !important; min-width: 0 !important;
10             padding: 0 !important; margin: 0 !important; background: white !important;
11           }
12           .source-report { border: 0 !important; box-shadow: none !important; }
13           .source-report .overflow-x-auto { overflow: visible !important; max-width: 100% !important; }
14           .source-report table {
15             display: table !important; width: 100% !important; min-width: 0 !important;
16             max-width: 100% !important; table-layout: fixed !important; font-size: 7pt !important;
17           }
18           .source-report th, .source-report td {
19             white-space: normal !important;
19 overflow-wrap: anywhere !important; word-break: break-word !important;
20             padding: 1mm !important; vertical-align: top !important;
21           }
22           .source-report tr, .source-report details { break-inside: avoid; }
23           .source-report details { display: block !important; }
24         }`}),a.jsxs("p",{className:"text-sm",children:["Allocated source ledger: ",r(((z=(M=u.data)==null?void 0:M.reconciliation)==null?void 0:z.sourceLedgerSpend)??null)," · Linked marketing fixed expenses: ",r(((W=(J=u.data)==null?void 0:J.reconciliation)==null?void 0:W.linkedFixedSpend)??null)," · Unassigned marketing fixed expenses: ",r(((Z=(Y=u.data)==null?void 0:Y.reconciliation)==null?void 0:Z.unassignedMarketingFixedSpend)??null),". Unassigned expenses remain in management overheads but cannot be charged to a particular source."]}),a.jsx("p",{className:"text-sm text-slate-600",children:"Lead outcomes below are grouped by the date the lead was created within this range. Won jobs and invoiced sales are separate metrics based on their own recognition dates, so their totals need not match won leads. Historical losses without a recorded reason remain unrecorded; no reason is inferred."}),u.isFetching&&a.jsx("p",{children:"Loading comparison…"}),a.jsxs("details",{children:[a.jsx("summary",{children:"Definitions and limitations"}),a.jsx("ul",{className:"list-disc pl-5 space-y-2 text-sm mt-2",children:(X=u.data)==null?void 0:X.definitions.map(e=>a.jsx("li",{children:e},e))})]}),!!((ae=(ee=u.data)==null?void 0:ee.excludedInvoices)!=null&&ae.length)&&a.jsxs("details",{className:"source-excluded border border-amber-200 rounded p-3",children:[a.jsxs("summary",{children:["Excluded invoice records (",u.data.excludedInvoices.length,")"]}),a.jsx("p",{className:"text-sm",children:"Undated records cannot be assigned to this period and remain visible here for review."}),u.data.excludedInvoices.map(e=>a.jsxs("p",{className:"text-sm mt-2",children:[a.jsx("a",{className:"underline",href:`/admin?tab=invoices&invoice=${e.id}`,children:e.invoiceNumber})," — ",e.detail]},e.id))]}),a.jsx("p",{className:"text-sm text-amber-900 bg-amber-50 p-3",children:"Source spend is in-period allocation; paid conversions are the selected intake cohort paid by today. These are different date bases. Cost per cohort event is a comparison, not exact acquisition ROI. Sales are invoiced on issue dates, not payment receipts. Direct-cost and refund completeness is not certified; actual return and profit are unavailable."}),a.jsx("div",{className:"overflow-x-auto",children:a.jsxs("table",{className:"w-full text-sm",children:[a.jsx("thead",{children:a.jsx("tr",{children:["Source","Spend ex VAT","Intake leads","Quoted leads","Paid leads","Paid rate","Cost / lead","Cost / quote","Cost / paid lead","Invoiced sales ex VAT","Booked sales","Booked value ex VAT","Average booked sale ex VAT","Time to paid sale","Open / lost"].map(e=>a.jsx("th",{className:"p-2 text-left border-b",children:e},e))})}),a.jsx("tbody",{children:C.map(e=>a.jsxs("tr",{className:"border-b",children:[a.jsxs("td",{className:"p-2",children:[e.name,e.archived?" (archived)":""]}),a.jsxs("td",{className:"p-2",children:[r(e.spend),a.jsxs("small",{className:"block",children:["Ledger ",r(e.periodSpend)," · Fees ",r(e.jobFees)," · Existing fixed ",r(e.fixedSpend)]})]}),a.jsx("td",{className:"p-2",children:e.leads}),a.jsx("td",{className:"p-2",children:e.quotedLeads}),a.jsx("td",{className:"p-2",children:e.paidLeads}),a.jsx("td",{className:"p-2",children:e.paidConversionRate==null?"Unavailable":`${(e.paidConversionRate*100).toFixed(1)}%`}),a.jsx("td",{className:"p-2",children:r(e.costPerLead)}),a.jsx("td",{className:"p-2",children:r(e.costPerQuote)}),a.jsx("td",{className:"p-2",children:r(e.costPerPaidLead)}),a.jsx("td",{className:"p-2",children:r(e.invoicedSales)}),a.jsx("td",{className:"p-2",children:e.jobsWon}),a.jsx("td",{className:"p-2",children:r(e.bookedValueExVat)}),a.jsx("td",{className:"p-2",children:r(e.averageBookedSaleExVat)}),a.jsx("td",{className:"p-2",children:e.timeToSaleDays==null?"Unavailable":`${e.timeToSaleDays} days`}),a.jsxs("td",{className:"p-2",children:[e.openLeads," / ",e.lostLeads]})]},e.key))})]})}),a.jsx("p",{className:"text-xs",children:"Average booked sale uses distinct accepted-quote, direct-order and independent-invoice lifecycles, ex VAT, on booked-sale dates. Invoiced sales are a separate issued-date measure. Missing booked values make the average unavailable; staged invoices never count as extra booked sales."}),a.jsx("h3",{className:"font-semibold",children:"Underlying jobs, invoice documents and costs"}),C.map(e=>{var d;return a.jsxs("details",{className:"border rounded p-3",open:!0,children:[a.jsxs("summary",{children:[e.name," · ",e.leads," intake leads · ",e.jobs.length," booked sales · ",e.costs.length+e.linkedFixedExpenses.length," cost entr
24ies"]}),a.jsxs("div",{className:"space-y-2 mt-2",children:[a.jsxs("p",{children:[a.jsx("strong",{children:"Estimated contribution after recorded spend:"})," ",r(e.estimatedContribution)," · ",a.jsx("strong",{children:"Actual after spend:"})," ",r(e.actualContribution)," (not certified). Estimated contribution uses dated recognised jobs and recorded costs, not invoiced sales; missing costs and refunds can change it."]}),a.jsxs("p",{children:[a.jsx("strong",{children:"Lost reasons:"})," ",he.map(s=>{var c;return`${xe[s]} ${((c=e.lossReasons)==null?void 0:c[s])??0}`}).join(" · ")," · Unrecorded ",e.unrecordedLossReasons??0]}),(d=e.leadDetails)==null?void 0:d.map(s=>a.jsxs("p",{children:["Lead ",s.kind," #",s.id," · ",String(s.createdAt).slice(0,10)," · ",s.status," ",s.firstPaidAt?String(s.firstPaidAt).slice(0,10):""," · ",s.quoteIds.map(c=>a.jsxs("a",{className:"underline mr-2",href:`/admin/quotes/${c}`,children:["Quote #",c]},c))]},`${s.kind}:${s.id}`)),e.jobs.map(s=>a.jsxs("a",{className:"block underline",href:s.href,children:[s.kind," #",s.id," · booked ex VAT ",r(s.bookedValueExVat)]},`${s.kind}:${s.id}`)),e.invoices.map(s=>a.jsxs("a",{className:"block underline",href:`/admin?tab=invoices&invoice=${s.id}`,children:["Invoice ",s.reference||s.id," · ",r(s.value)]},s.id)),e.costs.map(s=>a.jsxs("p",{children:["Cost #",s.id," · ",s.description," · ",s.periodStart," – ",s.periodEnd," · ",r(s.amountPence/100)," (",s.vatBasis,", ",s.frequency,")"]},s.id)),e.linkedFixedExpenses.map(s=>a.jsxs("p",{children:["Fixed expense #",s.id," · ",s.label," · ",r(s.monthlyAmount),"/month"]},`fixed:${s.id}`))]})]},e.key)})]}),a.jsxs("details",{className:"source-audit border rounded p-4",children:[a.jsx("summary",{children:"Recent audit history (latest 200 changes)"}),(se=F.data)==null?void 0:se.map(e=>a.jsxs("div",{className:"border-b py-2 text-sm",children:[a.jsx("strong",{children:e.action})," · ",e.actorUsername," · ",new Date(e.createdAt).toLocaleString("en-GB"),a.jsx("pre",{className:"whitespace-pre-wrap break-all",children:JSON.stringify(e.detail,null,2)})]},e.id))]})]})})}export{Le 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.