PageSourceSearch

https://estimatekit.com/assets/Estimates-BKWCMDZS.js

js estimatekit.com collected 2026-10-04 03:34:06 UTC 13,321 bytes, 11 lines download raw bytes

1import{A as O,k as P,r as x,m as R,C as H,j as t,o as q}from"./index-CbvCveKN.js";import{D as G,P as I,e as k,f as z}from"./PageContainer-Bx7SVsdy.js";import{P as B}from"./PageHeader-ohyr15TW.js";import{F as W}from"./FilterChips-CYAfenlT.js";import{E as S}from"./EmptyState-CvKdOS6b.js";import{S as Z}from"./SearchInput-CwtZ1bZ_.js";import{S as J}from"./skeleton-CQrTucTw.js";import{S as b,b as K,c as $,d as C,e as Q,s as Y}from"./pipeline-57THQ7iX.js";import{d as X}from"./differenceInDays-DKaeRypT.js";import{S as ee}from"./send-gD9LtlB-.js";import{C as te}from"./calendar-clock-CsLtIGEm.js";import{R as ne}from"./users-BkZzL3s4.js";import{F as se}from"./file-text-DDhZ7a0t.js";import{P as ae}from"./plus-kYCBPFxU.js";import{S as re}from"./search-fqqyqjqf.js";import{p as _}from"./parseISO-B0WEjCD3.js";import{f as ie}from"./format-BZAqQT85.js";import"./check-Bjw6cCk6.js";import"./index-Jf4OHjGl.js";import"./chevron-right-f4vsMuAf.js";import"./triangle-alert-BJBV5PBt.js";import"./en-US-wdCzBwgh.js";import"./layout-dashboard-rEexJXnQ.js";import"./ek-mark-light-Y4_w-cFG.js";import"./plug-BAhKXAxN.js";import"./chevron-down-yKD6BMcU.js";import"./GrainGradient-kJbOtAvv.js";import"./differenceInCalendarDays-BmAYwV3_.js";/**
2 * @license lucide-react v0.462.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const oe=O("Trophy",[["path",{d:"M6 9H4.5a2.5 2.5 0 0 1 0-5H6",key:"17hqa7"}],["path",{d:"M18 9h1.5a2.5 2.5 0 0 0 0-5H18",key:"lmptdp"}],["path",{d:"M4 22h16",key:"57wxv0"}],["path",{d:"M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22",key:"1nw9bq"}],["path",{d:"M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22",key:"1np0yb"}],["path",{d:"M18 2H6v7a6 6 0 0 0 12 0V2Z",key:"u46fv3"}]]),U=i=>`/estimates/${i.id}/${i.status==="draft"?"add-items":"view"}`,F=i=>`$${i.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}`,m=i=>`$${i.toLocaleString("en-US",{maximumFractionDigits:0})}`,de=i=>{const l=Q(i);return{min:l.min,max:l.max,value:l.value,multi:l.options>1}},M=i=>{const l=i?_(i):null;return l&&!Number.isNaN(l.getTime())?z(l,{addSuffix:!0}):"just now"},Le=()=>{const i=P(),[l,V]=x.useState(""),[T]=R(),[h,w]=x.useState(()=>{const e=T.get("tab");return e&&b.some(n=>n.value===e)?e:"all"}),[f,A]=x.useState("recent"),{data:v=[],isLoading:D}=H({queryKey:["all-estimates"],queryFn:async()=>{const{data:e,error:n}=await q.from("estimates").select(`id, estimate_number, client_name, job_description, status, created_at, sent_at, viewed_at, approved_at, account_id, pricing_type,
7          valid_until, version, superseded_by, approved_tier_id,
8          estimate_settings ( total ),
9          estimate_tiers!estimate_tiers_estimate_id_fkey ( id, total, tier_number, is_recommended ),
10          jobs!jobs_estimate_id_fkey ( id, job_number, status, scheduled_date ),
11          invoices!invoices_estimate_id_fkey ( id, status, kind )`).order("created_at",{ascending:!1});if(n)throw n;return e||[]}}),c=x.useMemo(()=>v.map(e=>{var y;const n=de(e),d=(e.jobs||[]).find(g=>!/^[A-Za-z]+-\d+-\d+$/.test(g.job_number))||((y=e.jobs)==null?void 0:y[0])||null,r=(e.invoices||[]).find(g=>g.kind!=="deposit")||null,o=K({estimate:e,job:d,invoice:r}),a=o==="sent"||o==="viewed",p=a&&e.valid_until?X(_(e.valid_until+"T23:59:59"),new Date):null,j=e.approved_tier_id?(e.estimate_tiers||[]).find(g=>g.id===e.approved_tier_id):null,L=e.approved_at?Number((j==null?void 0:j.total)??n.value):0;return{...e,...n,stage:o,job:d,invoice:r,isOpen:a,daysLeft:p,wonValue:L,expiring:p!=null&&p<=7}}),[v]),s=x.useMemo(()=>{const e=c.filter(a=>a.isOpen),n=c.filter(a=>a.approved_at||a.stage==="declined"||a.stage==="expired"),d=n.filter(a=>!!a.approved_at),r=c.filter(a=>a.stage==="won"),o=c.filter(a=>a.stage==="done");return{openCount:e.length,openValue:e.reduce((a,p)=>a+p.value,0),winRate:n.length?Math.round(d.length/n.length*100):null,expiring:e.filter(a=>a.expiring).length,wonUnscheduled:r.length,wonUnscheduledValue:r.reduce((a,p)=>a+p.wonValue,0),doneUninvoiced:o.length,doneUninvoicedValue:o.reduce((a,p)=>a+p.wonValue,0)}},[c]),E=x.useMemo(()=>{const e={};for(const n of b)e[n.value]=n.value==="all"?c.length:c.filter(d=>n.stages.includes(d.stage)).length;return e},[c]),u=x.useMemo(()=>{const e=l.trim().toLowerCase(),n=b.find(r=>r.value===h),d=c.filter(r=>h!=="all"&&n&&!n.stages.includes(r.stage)||h==="all"&&r.stage==="superseded"&&!e?!1:e?[r.client_name,r.job_description,r.estimate_number,r.id.slice(0,8)].some(o=>o==null?void 0:o.toLowerCase().includes(e)):!0);return f==="value"?[...d].sort((r,o)=>o.value-r.value):d},[c,l,h,f]),N=e=>{var n;return e.expiring&&e.isOpen?`Expires in ${Math.max(0,e.daysLeft||0)}d · follow up`:e.stage==="scheduled"&&((n=e.job)!=null&&n.scheduled_date)?`Job ${e.job.job_number} · ${new Date(e.job.scheduled_date+"T12:00:00").toLocaleDateString("en-US",{month:"short",day:"numeric"})}`:Y(e.stage)};return t.jsxs("div",{className:"min-h-screen bg-background",children:[t.jsx(G,{}),t.jsxs(I,{width:"wide",children:[t.jsx(B,{title:"Estimates",description:"Your pi
11peline: what's out, what's won, and what still needs a date or an invoice."}),t.jsxs("div",{className:"space-y-6 md:space-y-8",children:[t.jsx("div",{className:"grid grid-cols-2 gap-px overflow-hidden rounded-xl border border-ink/[0.06] bg-ink/[0.06] md:grid-cols-4",children:[{label:"Out for approval",value:s.openCount?`${m(s.openValue)}`:"0",sub:s.openCount?`${s.openCount} estimate${s.openCount===1?"":"s"}${s.expiring?` · ${s.expiring} expiring soon`:""}`:"nothing pending",icon:ee,warn:s.expiring>0,filter:"sent"},{label:"Won, not scheduled",value:s.wonUnscheduled?m(s.wonUnscheduledValue):"0",sub:s.wonUnscheduled?`${s.wonUnscheduled} job${s.wonUnscheduled===1?"":"s"} need a date`:"all scheduled",icon:te,warn:s.wonUnscheduled>0,filter:"won"},{label:"Done, not invoiced",value:s.doneUninvoiced?m(s.doneUninvoicedValue):"0",sub:s.doneUninvoiced?`${s.doneUninvoiced} job${s.doneUninvoiced===1?"":"s"} to bill`:"nothing to bill",icon:ne,warn:s.doneUninvoiced>0,filter:"done"},{label:"Win rate",value:s.winRate==null?"—":`${s.winRate}%`,sub:"of decided estimates",icon:oe,warn:!1,filter:null}].map(e=>t.jsxs("button",{type:"button",onClick:()=>e.filter&&w(e.filter),className:`flex min-w-0 flex-col gap-1.5 bg-card px-4 py-4 text-left transition-colors md:gap-2 md:px-5 md:py-5 ${e.filter?"hover:bg-ink/[0.04]":"cursor-default"}`,children:[t.jsx("p",{className:"text-[12.5px] text-foreground-secondary md:text-[13px]",children:e.label}),t.jsx("p",{className:`truncate font-mono text-[17px] font-medium tracking-[-0.02em] md:text-[18px] ${e.warn?"text-warn":"text-foreground"}`,children:e.value}),t.jsx("p",{className:"text-[12px] text-foreground-tertiary md:text-[12.5px]",children:e.sub})]},e.label))}),t.jsxs("div",{className:"flex flex-col gap-3.5",children:[t.jsx(Z,{value:l,onChange:V,placeholder:"Search estimates"}),t.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[t.jsx(W,{value:h,onChange:w,options:b.map(e=>({value:e.value,label:e.label,count:E[e.value]??0}))}),t.jsx("div",{role:"tablist",className:"flex shrink-0 self-start rounded-xl border border-ink/[0.06] bg-card p-[3px]",children:[["recent","Recent"],["value","Value"]].map(([e,n])=>t.jsx("button",{role:"tab","aria-selected":f===e,onClick:()=>A(e),className:`h-8 min-h-0 rounded-md px-3.5 text-[13px] font-semibold transition-colors ${f===e?"bg-ink/[0.08] text-foreground":"text-foreground-secondary hover:text-foreground"}`,children:n},e))})]})]}),D?t.jsx("div",{className:"flex flex-col gap-px overflow-hidden rounded-xl border border-ink/[0.06] bg-ink/[0.05]",children:[1,2,3,4].map(e=>t.jsx("div",{className:"bg-card px-5 py-4",children:t.jsx(J,{className:"h-[52px] rounded-xl"})},e))}):u.length===0?v.length===0?t.jsx(S,{icon:se,title:"No estimates yet",description:"Build one in a couple of minutes from your price book.",action:{label:"New estimate",onClick:()=>i("/estimates/new"),icon:ae}}):t.jsx(S,{icon:re,title:"No estimates match",description:"Try another search or stage."}):t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"hidden overflow-hidden rounded-[14px] border border-ink/[0.07] bg-white shadow-[0_1px_2px_rgba(24,24,27,0.04)] md:block",children:[t.jsxs("div",{role:"row",className:"grid h-9 grid-cols-[minmax(0,2.2fr)_110px_minmax(0,1.6fr)_120px_110px_130px] items-center border-b border-ink/[0.07] bg-[#FAFAF9] px-4 text-[12px] text-foreground-tertiary",children:[t.jsx("span",{children:"Customer"}),t.jsx("span",{children:"Estimate"}),t.jsx("span",{children:"Next step"}),t.jsx("span",{children:"Sent"}),t.jsx("span",{children:"Status"}),t.jsx("span",{className:"text-right",children:"Total"})]}),u.map(e=>{var r;const n=N(e),d=e.expiring&&e.isOpen||e.stage==="won"||e.stage==="done"||e.stage==="overdue";return t.jsxs("button",{role:"row",type:"button",onClick:()=>i(U(e)),className:"grid w-full grid-cols-[minmax(0,2.2fr)_110px_minmax(0,1.6fr)_120px_110px_130px] items-center border-b border-ink/[0.05] px-4 py-2.5 text-left text-[13px] transition-colors last:border-b-0 hover:bg-[#FAFAF9]",children:[t.jsxs("span",{className:"flex min-w-0 flex-col pr-3",children:[t.jsxs("span",{className:"flex min-w-0 items-center gap-2",children:[t.jsx("span",{className:"truncate text-foreground",children:e.client_name}),t.jsx(k,{id:e.id,compact:!0}),(e.version??1)>1&&t.jsxs("span",{className:"shrink-0 rounded-[5px] bg-ink/[0.06] px-1.5 text-[10.5px] text-foreground-secondary",children:["v",e.version]})]}),t.jsx("span",{className:"truncate text-[12px] text-foreground-tertiary",children:e.job_description||"No description"})]}),t.jsx("span",{className:"ek-num truncate text-foreground-secondary",children:e.estimate_number||`#${e.id.slice(0,8).toUpperCase()}`}),t.jsx("span",{className:`truncate pr-3 ${d?"text-attn":"text-foreground-tertiary"}`,children:n||"—"}),t.jsx("span",{className:"ek-num truncate text-foreground-secondary",children:e.sent_at?ie(_(e.sent_at),"MMM d"):"Not sent"}),t.jsx("span",{children:t.jsx("span",{className:`rounded-md px-1.5 py-0.5 text-[11.5px] font-medium whitespace-nowrap ${$[e.stage]}`,children:C[e.stage]})}),t.jsxs("span",{className:"text-right",children:[t.jsx("span",{className:"ek-num block text-foreground",children:e.multi&&!e.approved_at?`${m(e.min)}–${m(e.max)}`:F(e.approved_at&&e.wonValue||e.value)}),e.multi&&!e.approved_at&&t.jsxs("span",{className:"block text-[11px] text-foreground-tertiary",children:[(r=e.estimate_tiers)==null?void 0:r.length," options"]})]})]},e.id)}),t.jsxs("div",{className:"grid h-10 grid-cols-[minmax(0,2.2fr)_110px_minmax(0,1.6fr)_120px_110px_130px] items-center border-t border-ink/[0.07] bg-[#FAFAF9] px-4 text-[12.5px] text-foreground-secondary",children:[t.jsxs("span",{className:"ek-num",children:[u.length," ",u.length===1?"estimate":"estimates"]}),t.jsx("span",{}),t.jsx("span",{}),t.jsx("span",{}),t.jsx("span",{}),t.jsx("span",{className:"ek-num text-right text-foreground",children:m(u.reduce((e,n)=>e+(n.approved_at&&n.wonValue||n.value)||0,0))})]})]}),t.jsx("div",{className:"ek-zebra flex flex-col gap-px overflow-hidden rounded-xl border border-ink/[0.06] bg-ink/[0.05] md:hidden",children:u.map(e=>{var o;const n=e.isOpen&&e.sent_at?`sent ${M(e.sent_at)}`:M(e.created_at),d=N(e),r=e.expiring&&e.isOpen||e.stage==="won"||e.stage==="done"||e.stage==="overdue";return t.jsxs("button",{type:"button",onClick:()=>i(U(e)),className:"flex w-full cursor-pointer items-center gap-4 bg-card px-4 py-4 text-left transition-colors hover:bg-ink/[0.04] active:bg-ink/[0.04] md:px-5",children:[t.jsxs("div",{className:"flex min-w-0 flex-1 flex-col gap-1",children:[t.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[t.jsx("span",{className:"truncate text-[14px] font-semibold text-foreground",children:e.client_name}),t.jsx(k,{id:e.id,compact:!0}),(e.version??1)>1&&t.jsxs("span",{className:"hidden shrink-0 rounded-[5px] bg-ink/[0.08] px-1.5 font-mono text-[10.5px] text-foreground-secondary sm:inline",children:["v",e.version]})]}),t.jsxs("p",{className:"flex min-w-0 items-baseline gap-1.5 whitespace-nowrap text-[13px] text-foreground-secondary",children:[t.jsx("span",{className:"shrink-0 font-mono text-[12px]",children:e.estimate_number||`#${e.id.slice(0,8).toUpperCase()}`}),t.jsx("span",{className:"shrink-0",children:"·"}),t.jsx("span",{className:"min-w-0 truncate",children:e.job_description||"No description"}),t.jsxs("span",{className:"shrink-0",children:["· ",n]})]}),d&&t.jsx("p",{className:`truncate text-[12px] font-medium ${r?"text-cta-orange":"text-foreground-tertiary"}`,children:d})]}),t.jsxs("div",{className:"flex shrink-0 flex-col items-end gap-[7px]",children:[t.jsxs("div",{className:"text-right",children:[t.jsx("div",{className:"font-mono text-[14px] font-medium text-foreground",children:e.multi&&!e.approved_at?`${m(e.min)}–${m(e.max)}`:F(e.approved_at&&e.wonValue||e.value)}),e.multi&&!e.approved_at&&t.jsxs("div",{className:"text-[11.5px] text-foreground-tertiary",children:[(o=e.estimate_tiers)==null?void 0:o.length," options"]})]}),t.jsx("span",{className:`rounded-[5px] px-1.5 py-px text-[11.5px] font-medium whitespace-nowrap ${$[e.stage]}`,children:C[e.stage]})]})]},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.