1import{e as W,f as V,j as t,a1 as Z,r as g,t as m,X as G,V as X}from"./index-D2G60a0R.js";import{u as H}from"./useQuery-CjRW_EZA.js";import{u as J}from"./useMutation-B0P05SgI.js";import{u as x}from"./useServerFn-CXyRoyBF.js";import{A as Y}from"./AdminShell-B4CM9Fci.js";import{u as ee}from"./usePackages-BCbsJuRP.js";import{l as te,c as ae,u as ne,d as ie,e as se,a as oe}from"./invoices.functions-q3fNwmsM.js";import{r as le}from"./auth-middleware-CM7CnJkt.js";import{f as y}from"./format-date-B_BRYAWJ.js";import{P as L}from"./plus-Ch6odldt.js";import{C as re}from"./copy-DCBtMA09.js";import{D as ce}from"./download-CYPQOLTo.js";import{S as de}from"./send-C8BtMyWQ.js";import{T as me}from"./trash-2-DVf2GQzF.js";import"./admin.functions-CHf-M9wf.js";import"./shopping-bag-Bi3HI93O.js";const ue=W({method:"POST"}).middleware([le]).handler(V("2396ed5c103c51c2d2f9ae6d03c733991eb6e3a3b97adcbd819f5a88c48209b6"));async function M(n){return ue({data:n})}function pe(){const{packages:n}=ee();return g.useMemo(()=>[...n.filter(r=>typeof r.priceCents=="number").map(r=>({id:`pkg_${r.slug}`,label:r.name,amountCents:r.priceCents})),{id:"addon_photo_booth",label:"Photo Booth Add-on",amountCents:3e4}],[n])}function _(){return{key:crypto.randomUUID(),catalogId:"",description:"",amountCents:0,quantity:1}}function xe(n,r){return!r||n==="paid"||n==="void"?!1:r<new Date().toISOString().slice(0,10)}function ge(n){if(!n)return 0;const r=new Date().toISOString().slice(0,10);return Math.max(0,Math.floor((Date.parse(`${r}T00:00:00Z`)-Date.parse(`${n}T00:00:00Z`))/864e5))}function h(n){return`$${(n/100).toLocaleString(void 0,{minimumFractionDigits:2,maximumFractionDigits:2})}`}function Le(){return t.jsx(Y,{title:"Invoices",eyebrow:"Custom billing",children:n=>t.jsx(be,{canEdit:n.canEdit})})}function be({canEdit:n}){const r=pe(),N=x(te),j=x(ae),w=x(ne),C=x(ie),P=x(se),T=x(oe),b=Z(),D=H({queryKey:["invoices"],queryFn:()=>N()}),[A,k]=g.useState(!1),[l,p]=g.useState({clientName:"",clientEmail:"",billingEmail:"",dueDate:"",notes:""}),[f,u]=g.useState([_()]),[S,I]=g.useState(null),v=g.useMemo(()=>f.reduce((e,a)=>e+Math.max(0,a.amountCents)*Math.max(1,a.quantity),0),[f]),B=()=>{p({clientName:"",clientEmail:"",billingEmail:"",dueDate:"",notes:""}),u([_()])},$=J({mutationFn:async()=>{const e=f.map(i=>({...i,description:i.description.trim()})).filter(i=>i.description&&i.amountCents>0&&i.quantity>0);if(e.length===0)throw new Error("Add at least one line item");if(v<100)throw new Error("Total must be at least $1");const a=e.map(i=>i.quantity>1?`${i.description} à ${i.quantity}`:i.description).join(" · ").slice(0,500),c=[e.map(i=>`⢠${i.description}${i.quantity>1?` à ${i.quantity}`:""} â $${(i.amountCents*i.quantity/100).toFixed(2)}`).join(` 2`),l.notes.trim()].filter(Boolean).join(` 3 4`).slice(0,2e3),o=await j({data:{clientName:l.clientName.trim(),clientEmail:l.clientEmail.trim(),billingEmail:l.billingEmail.trim(),description:a,amountCents:v,dueDate:l.dueDate,notes:c}}),d=l.billingEmail.trim()||l.clientEmail.trim();try{await M({templateName:"invoice",recipientEmail:d,idempotencyKey:`invoice-${o.id}`,templateData:{clientName:l.clientName.trim(),description:a,amountFormatted:h(v),dueDate:l.dueDate||null,notes:c||null,payUrl:`${window.location.origin}/pay/${o.id}`,pdfUrl:`${window.location.origin}/api/public/invoices/${o.id}/pdf`,siteName:"Little Wild Mobile Farm"}}),m.success(`Invoice created and emailed to ${d}.`)}catch(i){m.error(`Invoice created, but email failed to send: ${i instanceof Error?i.message:"unknown error"}`)}return o},onSuccess:()=>{B(),k(!1),b.invalidateQueries({queryKey:["invoices"]})},onError:e=>m.error(e instanceof Error?e.message:"Couldn't create invoice")}),q=D.data??[];function z(e){const a=`${window.location.origin}/pay/${e}`;navigator.clipboard.writeText(a).then(()=>m.success("Pay link copied"),()=>m.error("Couldn't copy â copy manually: "+a))}async function F(e,a){try{await w({data:{id:e,status:a}}),b.invalidateQueries({queryKey:["invoices"]})}catch{m.error("Couldn't update status")}}async function K(e){try{const a=e.status==="paid";await M({templateName:a?"invoice-receipt":"invoice",recipientEmail:e.client_email,idempotencyKey:`invoice-${e.id}-${a?"receipt":"resend"}-${Date.now()}`,templateData:a?{clientName:e.client_name,description:e.description,amountFormatted:h(e.amount_cents),paidDate:e.paid_at?y(e.paid_at):null,notes:null,siteName:"Little Wild Mobile Farm"}:{clientName:e.client_name,description:e.description,amountFormatted:h(e.amount_cents),dueDate:e.due_date,notes:null,payUrl:`${window.location.origin}/pay/${e.id}`,pdfUrl:`${window.location.origin}/api/public/invoices/${e.id}/pdf`,invoiceNumber:e.invoice_number??null,siteName:"Little Wild Mobile Farm"}}),m.success(a?`Receipt sent to ${e.client_email}`:`Invoice re-sent to ${e.client_email}`)}catch(a){m.error(a instanceof Error?a.message:"Couldn't send email")}}async function Q(e){const a=e.billing_email||e.client_email,s=window.prompt("Send this invoice to (leave as-is to use the saved address):",a);if(s===null)return;const c=s.trim()===a?"":s.trim();I(e.id);try{const o=await P({data:{id:e.id,overrideEmail:c}});m.success(`Invoice emailed to ${o.recipient}`),b.invalidateQueries({queryKey:["invoices"]})}catch(o){m.error(o instanceof Error?o.message:"Couldn't send invoice")}finally{I(null)}}async function R(e){const a=window.prompt("Billing email (accounts payable). Leave blank to use the client email:",e.billing_email??"");if(a!==null)try{await T({data:{id:e.id,billingEmail:a.trim()}}),m.success("Billing email updated"),b.invalidateQueries({queryKey:["invoices"]})}catch(s){m.error(s instanceof Error?s.message:"Couldn't update billing email")}}async function U(e){if(confirm("Delete this invoice? This cannot be undone."))try{await C({data:{id:e}}),b.invalidateQueries({queryKey:["invoices"]})}catch{m.error("Couldn't delete")}}return t.jsxs("div",{className:"space-y-6",children:[n&&t.jsx("div",{className:"flex justify-end",children:t.jsxs("button",{onClick:()=>k(e=>!e),className:"inline-flex items-center gap-2 rounded-full bg-sage-deep px-5 py-2 text-sm text-cream hover:bg-ink transition-colors",children:[t.jsx(L,{className:"size-4"})," New invoice"]})}),A&&n&&t.jsxs("form",{onSubmit:e=>{e.preventDefault(),$.mutate()},className:"rounded-2xl border border-tan/40 bg-card p-5 shadow-soft grid gap-4 sm:grid-cols-2",children:[t.jsx(E,{label:"Client name",value:l.clientName,onChange:e=>p({...l,clientName:e}),required:!0,maxLength:120}),t.jsx(E,{label:"Client email",type:"email",value:l.clientEmail,onChange:e=>p({...l,clientEmail:e}),required:!0,maxLength:255}),t.jsxs("label",{className:"sm:col-span-2 block",children:[t.jsx("span",{className:"text-[11px] uppercase tracking-widest text-wood/55 font-semibold",children:"Send invoice to (billing email)"}),t.jsx("input",{type:"email",value:l.billingEmail,maxLength:255,onChange:e=>p({...l,billingEmail:e.target.value}),className:"mt-1 w-full rounded-xl border border-tan/40 bg-cream/40 px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-sage"}),t.jsx("span",{className:"mt-1 block text-xs text-wood/55",children:"If the invoice should go to a different address than the client (e.g., accounts payable), enter it here."})]}),t.jsxs("div",{className:"sm:col-span-2",children:[t.jsxs("div",{className:"mb-2 flex items-center justify-between",children:[t.jsx("span",{className:"text-[11px] uppercase tracking-widest text-wood/55 font-semibold",children:"Line items"}),t.jsxs("button",{type:"button",onClick:()=>u(e=>[...e,_()]),className:"inline-flex items-center gap-1 rounded-full border border-tan/50 px-3 py-1 text-xs hover:bg-tan/10",children:[t.jsx(L,{className:"size-3"})," Add line"]})]}),t.jsx("div",{className:"space-y-2",children:f.map((e,a)=>t.jsxs("div",{className:"grid grid-cols-12 gap-2 items-start rounded-xl border border-tan/30 bg-cream/40 p-2",children:[t.jsxs("select",{value:e.catalogId,onChange:s=>{const c=s.target.value,o=r.find(d=>d.id===c);u(d=>d.map((i,O)=>O===a?{...i,catalogId:c,description:c==="custom"?"":o?o.label:"",amountCents:o?o.amountCents:c==="custom"?0:i.amountCents}:i))},className:"col-span-12 sm:col-span-4 rounded-lg border border-tan/40 bg-card px-2 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-sage",children:[t.jsx("option",{value:"",children:"Select serviceâ¦"}),r.map(s=>t.jsxs("option",{value:s.id,children:[s.label," â $",(s.amountCents/100).toFixed(0)]},s.id)),t.jsx("option",{value:"custom",children:"Custom line itemâ¦"})]}),t.jsx("input",{type:"text",placeholder:"Description",value:e.description,onChange:s=>u(c=>c.map((o,d)=>d===a?{...o,description:s.target.value}:o)),maxLength:200,className:"col-span-6 sm:col-span-4 rounded-lg border border-tan/40 bg-card px-2 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-sage"}),t.jsx("input",{type:"number",min:"1",step:"1",value:e.quantity,onChange:s=>u(c=>c.map((o,d)=>d===a?{...o,quantity:Math.max(1,parseInt(s.target.value)||1)}:o)),className:"col-span-3 sm:col-span-1 rounded-lg border border-tan/40 bg-card px-2 py-2 text-sm text-center focus:outline-none focus:ring-2 focus:ring-sage","aria-label":"Quantity"}),t.jsx("input",{type:"number",min:"0",step:"0.01",placeholder:"Amount",value:e.amountCents?(e.amountCents/100).toString():"",onCh
4ange:s=>{const c=parseFloat(s.target.value);u(o=>o.map((d,i)=>i===a?{...d,amountCents:Number.isFinite(c)?Math.round(c*100):0}:d))},className:"col-span-3 sm:col-span-2 rounded-lg border border-tan/40 bg-card px-2 py-2 text-sm text-right focus:outline-none focus:ring-2 focus:ring-sage"}),t.jsx("button",{type:"button",onClick:()=>u(s=>s.length>1?s.filter((c,o)=>o!==a):s),className:"col-span-12 sm:col-span-1 inline-flex items-center justify-center rounded-lg border border-tan/40 py-2 text-wood/60 hover:bg-destructive/10 hover:text-destructive","aria-label":"Remove line",disabled:f.length<=1,children:t.jsx(G,{className:"size-4"})})]},e.key))}),t.jsxs("div",{className:"mt-3 flex justify-end text-sm",children:[t.jsx("span",{className:"text-wood/60 mr-2",children:"Total:"}),t.jsx("span",{className:"font-display text-lg text-wood",children:h(v)})]})]}),t.jsx(E,{label:"Due date (optional)",type:"date",value:l.dueDate,onChange:e=>p({...l,dueDate:e})}),t.jsx("div",{}),t.jsxs("label",{className:"sm:col-span-2 block",children:[t.jsx("span",{className:"text-[11px] uppercase tracking-widest text-wood/55 font-semibold",children:"Notes (optional)"}),t.jsx("textarea",{value:l.notes,onChange:e=>p({...l,notes:e.target.value}),rows:3,maxLength:2e3,className:"mt-1 w-full rounded-xl border border-tan/40 bg-cream/40 px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-sage"})]}),t.jsxs("div",{className:"sm:col-span-2 flex justify-end gap-2",children:[t.jsx("button",{type:"button",onClick:()=>k(!1),className:"rounded-full border border-tan/50 px-4 py-2 text-sm hover:bg-tan/10",children:"Cancel"}),t.jsx("button",{type:"submit",disabled:$.isPending,className:"rounded-full bg-sage-deep px-5 py-2 text-sm text-cream hover:bg-ink disabled:opacity-60",children:$.isPending?"Creatingâ¦":"Create invoice"})]})]}),D.isLoading?t.jsx("div",{className:"py-10 text-center text-wood/50",children:"Loadingâ¦"}):q.length===0?t.jsxs("div",{className:"rounded-2xl border border-tan/40 bg-card p-10 text-center text-wood/60",children:[t.jsx("p",{className:"font-display text-xl text-wood",children:"No invoices yet"}),t.jsx("p",{className:"mt-2 text-sm",children:"Create one and share the private pay link with your client."})]}):t.jsx("div",{className:"overflow-hidden rounded-2xl border border-tan/40 bg-card shadow-soft",children:t.jsx("ul",{className:"divide-y divide-tan/30",children:q.map(e=>t.jsxs("li",{className:"p-4 flex flex-wrap items-start gap-3",children:[t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.invoice_number&&t.jsx("span",{className:"text-[11px] font-bold uppercase tracking-widest text-sage-deep",children:e.invoice_number}),t.jsx("span",{className:"font-medium text-wood",children:e.client_name}),t.jsx(fe,{status:e.status}),xe(e.status,e.due_date)&&t.jsxs("span",{className:"rounded-full bg-destructive/15 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider text-destructive",children:["Past due · ",ge(e.due_date),"d"]}),t.jsxs("span",{className:"text-sm text-wood/60",children:["· ",e.client_email]})]}),e.billing_email&&t.jsxs("div",{className:"mt-1 text-xs text-sage-deep",children:["Billing: ",e.billing_email]}),t.jsx("div",{className:"mt-1 text-sm text-wood/80",children:e.description}),t.jsxs("div",{className:"mt-1 text-xs text-wood/50",children:["Created ",y(e.created_at),e.due_date?` · Due ${y(e.due_date)}`:"",e.paid_at?` · Paid ${y(e.paid_at)}`:""]})]}),t.jsx("div",{className:"text-right",children:t.jsx("div",{className:"font-display text-xl text-wood",children:h(e.amount_cents)})}),t.jsxs("div",{className:"w-full flex flex-wrap gap-2 pt-2",children:[t.jsxs("button",{onClick:()=>z(e.id),className:"inline-flex items-center gap-1 rounded-full border border-tan/50 px-3 py-1.5 text-xs hover:bg-tan/10",children:[t.jsx(re,{className:"size-3"})," Copy pay link"]}),(e.status==="sent"||e.status==="paid")&&t.jsxs("a",{href:`/api/public/invoices/${e.id}/pdf`,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1 rounded-full border border-tan/50 px-3 py-1.5 text-xs hover:bg-tan/10",children:[t.jsx(ce,{className:"size-3"})," Download PDF"]}),n&&e.status!=="void"&&t.jsxs("button",{onClick:()=>Q(e),disabled:S===e.id,className:"inline-flex items-center gap-1 rounded-full border border-sage/50 bg-sage/10 px-3 py-1.5 text-xs hover:bg-sage/20 disabled:opacity-60",children:[t.jsx(de,{className:"size-3"})," ",S===e.id?"Sendingâ¦":"Email invoice"]}),n&&t.jsx("button",{onClick:()=>R(e),className:"rounded-full border border-tan/50 px-3 py-1.5 text-xs hover:bg-tan/10",children:e.billing_email?"Edit billing email":"Add billing email"}),n&&e.status!=="void"&&t.jsxs("button",{onClick:()=>K(e),className:"inline-flex items-center gap-1 rounded-full border border-tan/50 px-3 py-1.5 text-xs hover:bg-tan/10",children:[t.jsx(X,{className:"size-3"})," ",e.status==="paid"?"Resend receipt":"Resend to client"]}),n&&e.status!=="paid"&&t.jsx("button",{onClick:()=>F(e.id,"paid"),className:"rounded-full border border-sage/50 bg-sage/10 px-3 py-1.5 text-xs hover:bg-sage/20",children:"Mark paid"}),n&&e.status!=="void"&&e.status!=="paid"&&t.jsx("button",{onClick:()=>F(e.id,"void"),className:"rounded-full border border-tan/50 px-3 py-1.5 text-xs hover:bg-tan/10",children:"Void"}),n&&t.jsxs("button",{onClick:()=>U(e.id),className:"ml-auto inline-flex items-center gap-1 rounded-full border border-destructive/40 px-3 py-1.5 text-xs text-destructive hover:bg-destructive/10",children:[t.jsx(me,{className:"size-3"})," Delete"]})]})]},e.id))})})]})}function E({label:n,value:r,onChange:N,className:j="",...w}){return t.jsxs("label",{className:`block ${j}`,children:[t.jsx("span",{className:"text-[11px] uppercase tracking-widest text-wood/55 font-semibold",children:n}),t.jsx("input",{...w,value:r,onChange:C=>N(C.target.value),className:"mt-1 w-full rounded-xl border border-tan/40 bg-cream/40 px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-sage"})]})}function fe({status:n}){const r={draft:"bg-tan/40 text-wood",sent:"bg-butter text-ink",paid:"bg-sage-deep text-cream",void:"bg-destructive/15 text-destructive"};return t.jsx("span",{className:`rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider ${r[n]??"bg-cream text-wood"}`,children:n})}export{Le as component};
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.