PageSourceSearch

https://nextgennetworksolutions.com/static/js/737.9723cd4f.chunk.js

js nextgennetworksolutions.com collected 2026-10-09 01:40:36 UTC 37,153 bytes, 3 lines download raw bytes

1/*! For license information please see 737.9723cd4f.chunk.js.LICENSE.txt */
2"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[737],{1737(e,t,a){a.r(t),a.d(t,{default:()=>K});var s=a(9379),n=a(5043),l=a(9722),i=a(6328),r=a(1140),c=a(3390),d=a(2264),o=a(556),m=a(5949),u=a(7459),p=a(3416),x=a(6178),h=a(5598),g=a(9292),j=a(2024),v=a(7104),b=a(797),f=a(4459),N=a(6833),y=a(7784);const k=(0,y.A)("star",[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]]);var w=a(8006),_=a(1286),C=a(5731),S=a(764),A=a(1884),R=a(5746);const $=(0,y.A)("message-square-plus",[["path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",key:"1lielz"}],["path",{d:"M12 7v6",key:"lw1j43"}],["path",{d:"M9 10h6",key:"9gxzsh"}]]);var q=a(5505),F=a(9855),J=a(9581),T=a(5327),E=a(1360),L=a(7819),z=a(5087),M=a(579);const O="https://nextgen-staging.emergent.host",G=["{{name}}","{{first_word}}","{{address}}","{{phone}}","{{website}}","{{my_company}}","{{my_phone}}"],I=e=>{let{exportFilter:t}=e;
2const[a,u]=(0,n.useState)([]),[g,j]=(0,n.useState)(!0),[v,b]=(0,n.useState)(!1),[f,N]=(0,n.useState)(null),[y,k]=(0,n.useState)(!1),[w,_]=(0,n.useState)(null),[C,S]=(0,n.useState)(!1),[A,$]=(0,n.useState)(""),[J,z]=(0,n.useState)(50),I=async()=>{j(!0);try{const e=await l.A.get("".concat(O,"/api/admin/marketing/templates"),{withCredentials:!0});u(e.data||[])}catch(e){i.oR.error("Failed to load templates")}finally{j(!1)}};(0,n.useEffect)(()=>{I()},[]);const P=e=>{N(e||{name:"",subject:"",body_html:"<p>Hi {{first_word}},</p>\n<p>I run NextGen Network Solutions and I noticed your business at {{address}}\u2026</p>\n<p>Would you be open to a 10-minute chat?</p>",body_text:""}),b(!0)};return(0,M.jsxs)(r.Zp,{className:"p-5 border-border","data-testid":"marketing-templates-panel",children:[(0,M.jsxs)("div",{className:"flex items-start justify-between gap-3 mb-4 flex-wrap",children:[(0,M.jsxs)("div",{children:[(0,M.jsxs)("h3",{className:"font-bold uppercase tracking-tight flex items-center gap-2",children:[(0,M.jsx)(T.A,{className:"w-4 h-4 text-primary"}),"Outreach Templates"]}),(0,M.jsxs)("p",{className:"text-xs text-muted-foreground mt-1",children:["Templated emails sent via Resend. Auto-logs a contact on the business after a successful send. Variables: ",G.map(e=>(0,M.jsx)("code",{className:"text-primary mx-1",children:e},e))]})]}),(0,M.jsxs)("div",{className:"flex items-center gap-2",children:[(0,M.jsxs)(c.$,{size:"sm",variant:"outline",onClick:()=>k(!0),"data-testid":"marketing-bulk-send-open",disabled:!a.length,children:[(0,M.jsx)(R.A,{className:"w-3.5 h-3.5 mr-1.5"}),"Bulk Send"]}),(0,M.jsxs)(c.$,{size:"sm",onClick:()=>P(null),"data-testid":"marketing-template-new",children:[(0,M.jsx)(E.A,{className:"w-3.5 h-3.5 mr-1.5"}),"New Template"]})]})]}),g&&(0,M.jsx)("p",{className:"text-xs text-muted-foreground",children:"Loading\u2026"}),!g&&0===a.length&&(0,M.jsx)("p",{className:"text-xs text-muted-foreground py-3",children:"No templates yet. Create one to start outreach."}),(0,M.jsx)("div",{className:"space-y-2",children:a.map(e=>(0,M.jsxs)("div",{className:"flex items-start justify-between gap-3 p-3 rounded-md border border-border bg-muted/20","data-testid":"marketing-template-".concat(e.template_id),children:[(0,M.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,M.jsx)("p",{className:"font-bold text-sm",children:e.name}),(0,M.jsx)("p",{className:"text-[11px] font-mono text-muted-foreground truncate",children:e.subject}),e.unknown_variables&&e.unknown_variables.length>0&&(0,M.jsxs)(m.E,{variant:"outline",className:"mt-1 text-[10px] text-amber-400 border-amber-500/40",children:[(0,M.jsx)(L.A,{className:"w-3 h-3 mr-1 inline"}),"Unknown vars: ",e.unknown_variables.join(", ")]})]}),(0,M.jsxs)("div",{className:"flex items-center gap-1 shrink-0",children:[(0,M.jsx)(c.$,{size:"sm",variant:"outline",onClick:()=>P(e),"data-testid":"marketing-template-edit-".concat(e.template_id),children:(0,M.jsx)(q.A,{className:"w-3.5 h-3.5"})}),(0,M.jsx)(c.$,{size:"sm",variant:"ghost",onClick:()=>(async e=>{if(window.confirm('Delete template "'.concat(e.name,'"?')))try{await l.A.delete("".concat(O,"/api/admin/marketing/templates/").concat(e.template_id),{withCredentials:!0}),i.oR.success("Template deleted"),I()}catch(t){i.oR.error("Failed to delete")}})(e),className:"text-destructive",children:(0,M.jsx)(F.A,{className:"w-3.5 h-3.5"})})]})]},e.template_id))}),(0,M.jsx)(h.lG,{open:v,onOpenChange:e=>{e||(b(!1),N(null))},children:(0,M.jsxs)(h.Cf,{className:"bg-card border-border max-w-2xl max-h-[90vh] overflow-y-auto","data-testid":"marketing-template-dialog",children:[(0,M.jsx)(h.c7,{children:(0,M.jsx)(h.L3,{className:"text-xl font-bold uppercase",children:null!==f&&void 0!==f&&f.template_id?"Edit Template":"New Template"})}),f&&(0,M.jsxs)("div",{className:"space-y-4",children:[(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Template name"}),(0,M.jsx)(d.p,{value:f.name,onChange:e=>N((0,s.A)((0,s.A)({},f),{},{name:e.target.value})),placeholder:"e.g. Cold intro \u2014 local SMB",className:"bg-input","data-testid":"marketing-template-name"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Subject line"}),(0,M.jsx)(d.p,{value:f.subject,onChange:e=>N((0,s.A)((0,s.A)({},f),{},{subject:e.target.value})),placeholder:"Quick IT idea for {{name}}",className:"bg-input","data-testid":"marketing-template-subject"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"HTML body"}),(0,M.jsx)(p.T,{rows:10,value:f.body_html,onChange:e=>N((0,s.A)((0,s.A)({},f),{},{body_html:e.target.value})),className:"bg-input font-mono text-xs","data-testid":"marketing-template-body-html"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Plain-text fallback (optional)"}),(0,M.jsx)(p.T,{rows:4,value:f.body_text,onChange:e=>N((0,s.A)((0,s.A)({},f),{},{body_text:e.target.value})),className:"bg-input font-mono text-xs","data-testid":"marketing-template-body-text"})]}),(0,M.jsxs)("div",{className:"flex justify-end gap-2 pt-2",children:[(0,M.jsx)(c.$,{variant:"ghost",onClick:()=>{b(!1),N(null)},children:"Cancel"}),(0,M.jsx)(c.$,{onClick:async()=>{try{f.template_id?await l.A.put("".concat(O,"/api/admin/marketing/templates/").concat(f.template_id),f,{withCredentials:!0}):await l.A.post("".concat(O,"/api/admin/marketing/templates"),f,{withCredentials:!0}),i.oR.success("Template saved"),b(!1),N(null),I()}catch(a){var e,t;i.oR.error((null===(e=a.response)||void 0===e||null===(t=e.data)||void 0===t?void 0:t.detail)||"Failed to save")}},className:"font-bold uppercase","data-testid":"marketing-template-save",children:"Save Template"})]})]})]})}),(0,M.jsx)(h.lG,{open:y,onOpenChange:e=>{e||(k(!1),_(null))},children:(0,M.jsxs)(h.Cf,{className:"bg-card border-border max-w-lg","data-testid":"marketing-bulk-dialog",children:[(0,M.jsx)(h.c7,{children:(0,M.jsx)(h.L3,{className:"text-xl font-bold uppercase",children:"Bulk Send Outreach"})}),w?(0,M.jsxs)("div",{className:"space-y-3 text-sm",children:[(0,M.jsxs)("p",{children:[(0,M.jsx)("span",{className:"text-primary font-bold",children:"Sent:"})," ",w.sent_count]}),(0,M.jsxs)("p",{children:[(0,M.jsx)("span",{className:"text-amber-400 font-bold",children:"Skipped:"})," ",w.skipped_count]}),(0,M.jsxs)("p",{children:[(0,M.jsx)("span",{className:"text-red-500 font-bold",children:"Failed:"})," ",w.failed_count]}),w.skipped.length>0&&(0,M.jsxs)("details",{className:"text-xs",children:[(0,M.jsxs)("summary",{className:"cursor-pointer text-muted-foreground",children:["View skipped (",w.skipped.length,")"]}),(0,M.jsx)("ul",{className:"mt-2 space-y-1 max-h-40 overflow-y-auto",children:w.skipped.map((e,t)=>(0,M.jsxs)("li",{children:[e.name," \u2014 ",e.reason]},t))})]}),(0,M.jsx)(c.$,{variant:"outline",className:"w-full",onClick:()=>{k(!1),_(null)},children:"Close"})]}):(0,M.jsxs)("div",{className:"space-y-4",children:[(0,M.jsxs)("p",{className:"text-xs text-muted-foreground",children:["Sends to all businesses matching the export filter (",(0,M.jsx)("span",{className:"text-primary uppercase",children:t}),") that already have an email on file. Businesses without an email are skipped."]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Template"}),(0,M.jsxs)(x.l6,{value:A,onValueChange:$,children:[(0,M.jsx)(x.bq,{className:"bg-input","data-testid":"marketing-bulk-template-select",children:(0,M.jsx)(x.yv,{placeholder:"Pick a template"})}),(0,M.jsx)(x.gC,{children:a.map(e=>(0,M.jsx)(x.eb,{value:e.template_id,children:e.name},e.template_id))})]})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Max recipients (safety cap)"}),(0,M.jsx)(d.p,{type:"number",min:"1",max:"500",value:J,onChange:e=>z(e.target.value),className:"bg-input","data-testid":"marketing-bulk-limit"})]}),(0,M.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,M.jsx)(c.$,{variant:"ghost",onClick:()=>k(!1),children:"Cancel"}),(0,M.jsx)(c.$,{onClick:async()=>
2{if(!A)return i.oR.error("Pick a template");S(!0),_(null);try{const e=await l.A.post("".concat(O,"/api/admin/marketing/bulk-send"),{template_id:A,filter:t,limit:parseInt(J)||50},{withCredentials:!0});_(e.data),i.oR.success("Sent ".concat(e.data.sent_count,", skipped ").concat(e.data.skipped_count,", failed ").concat(e.data.failed_count))}catch(s){var e,a;i.oR.error((null===(e=s.response)||void 0===e||null===(a=e.data)||void 0===a?void 0:a.detail)||"Bulk send failed")}finally{S(!1)}},disabled:C,className:"font-bold uppercase","data-testid":"marketing-bulk-run",children:C?"Sending\u2026":"Send All"})]})]})]})})]})},P=e=>{let{open:t,onClose:a,business:s,onSent:r}=e;const[m,u]=(0,n.useState)([]),[p,g]=(0,n.useState)(""),[j,v]=(0,n.useState)(""),[b,f]=(0,n.useState)(null),[N,y]=(0,n.useState)(!1);(0,n.useEffect)(()=>{t&&(g(""),f(null),v((null===s||void 0===s?void 0:s.outreach_email)||""),l.A.get("".concat(O,"/api/admin/marketing/templates"),{withCredentials:!0}).then(e=>u(e.data||[])).catch(()=>i.oR.error("Failed to load templates")))},[t,s]);return(0,M.jsx)(h.lG,{open:t,onOpenChange:e=>!e&&a(),children:(0,M.jsxs)(h.Cf,{className:"bg-card border-border max-w-2xl max-h-[90vh] overflow-y-auto","data-testid":"marketing-send-dialog",children:[(0,M.jsx)(h.c7,{children:(0,M.jsxs)(h.L3,{className:"text-xl font-bold uppercase",children:["Send Email \xb7 ",null===s||void 0===s?void 0:s.name]})}),(0,M.jsxs)("div",{className:"space-y-4",children:[(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Template"}),(0,M.jsxs)(x.l6,{value:p,onValueChange:g,children:[(0,M.jsx)(x.bq,{className:"bg-input","data-testid":"marketing-send-template-select",children:(0,M.jsx)(x.yv,{placeholder:"Pick a template"})}),(0,M.jsx)(x.gC,{children:m.map(e=>(0,M.jsx)(x.eb,{value:e.template_id,children:e.name},e.template_id))})]})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Send to"}),(0,M.jsx)(d.p,{value:j,onChange:e=>v(e.target.value),placeholder:"[email protected]",className:"bg-input","data-testid":"marketing-send-to"}),!j&&(0,M.jsx)("p",{className:"text-[11px] text-amber-400 mt-1",children:"No email on file \u2014 type one above. We'll save it for next time."})]}),(0,M.jsxs)("div",{className:"flex gap-2",children:[(0,M.jsxs)(c.$,{size:"sm",variant:"outline",onClick:async()=>{if(p&&s)try{const e=await l.A.post("".concat(O,"/api/admin/marketing/templates/").concat(p,"/preview"),{place_id:s.place_id},{withCredentials:!0});f(e.data),!j&&e.data.to_email&&v(e.data.to_email)}catch(a){var e,t;i.oR.error((null===(e=a.response)||void 0===e||null===(t=e.data)||void 0===t?void 0:t.detail)||"Preview failed")}},disabled:!p,"data-testid":"marketing-send-preview-btn",children:[(0,M.jsx)(z.A,{className:"w-3.5 h-3.5 mr-1.5"}),"Preview"]}),(0,M.jsxs)(c.$,{size:"sm",onClick:async()=>{if(!p)return i.oR.error("Pick a template");y(!0);try{const e=await l.A.post("".concat(O,"/api/admin/marketing/").concat(s.place_id,"/send-email"),{template_id:p,to_email:j||void 0},{withCredentials:!0});e.data.ok?(i.oR.success("Sent \u2192 ".concat(e.data.to_email)),null===r||void 0===r||r(),a()):i.oR.error(e.data.error||"Send failed")}catch(n){var e,t;i.oR.error((null===(e=n.response)||void 0===e||null===(t=e.data)||void 0===t?void 0:t.detail)||"Send failed")}finally{y(!1)}},disabled:N||!p||!j,"data-testid":"marketing-send-confirm",children:[(0,M.jsx)(R.A,{className:"w-3.5 h-3.5 mr-1.5"}),N?"Sending\u2026":"Send Now"]})]}),b&&(0,M.jsxs)("div",{className:"bg-muted/30 border border-border rounded-md p-4 text-xs space-y-2","data-testid":"marketing-send-preview-output",children:[(0,M.jsx)("p",{className:"text-[10px] uppercase tracking-widest text-muted-foreground",children:"Subject"}),(0,M.jsx)("p",{className:"font-bold",children:b.subject}),(0,M.jsx)("p",{className:"text-[10px] uppercase tracking-widest text-muted-foreground mt-3",children:"Body"}),(0,M.jsx)("div",{className:"prose prose-invert prose-sm max-w-none",dangerouslySetInnerHTML:{__html:b.body_html}})]})]})]})})};var B=a(1529);const V="https://nextgen-staging.emergent.host",U={all:"All businesses",never:"Never contacted","12mo":"No contact in 12 months","24mo":"No contact in 24 months"},D=["","restaurant","cafe","lawyer","accounting","dentist","doctor","real_estate_agency","insurance_agency","car_dealer","car_repair","electrician","plumber","storage","gym","school","university","hair_care","beauty_salon","pharmacy","veterinary_care","pet_store","hardware_store","home_goods_store","furniture_store","florist","bicycle_store","book_store","clothing_store","shoe_store"],Z=e=>{let{open:t,business:a,onCancel:s,onConfirm:l}=e;
2const[r,m]=(0,n.useState)(""),[p,x]=(0,n.useState)(""),[g,j]=(0,n.useState)(!0),[v,b]=(0,n.useState)(!1);(0,n.useEffect)(()=>{t&&a&&(m(a.outreach_email||a.client_email||""),x(a.name||""),j(!0),b(!1))},[t,a]);return(0,M.jsx)(h.lG,{open:t,onOpenChange:e=>!e&&(null===s||void 0===s?void 0:s()),children:(0,M.jsxs)(h.Cf,{className:"bg-card border-border max-w-md","data-testid":"marketing-convert-dialog",children:[(0,M.jsx)(h.c7,{children:(0,M.jsxs)(h.L3,{className:"text-lg font-bold uppercase flex items-center gap-2",children:[(0,M.jsx)(A.A,{className:"w-5 h-5 text-primary"}),"Save as Current Client"]})}),(0,M.jsxs)("div",{className:"space-y-4",children:[(0,M.jsxs)("p",{className:"text-xs text-muted-foreground",children:["Creates a client account for ",(0,M.jsx)("span",{className:"text-foreground font-bold",children:null===a||void 0===a?void 0:a.name}),g&&" and sends them a Google-OAuth invitation email."," You can manage their tickets, quotes, and invoices from the standard admin tabs after conversion."]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Client name"}),(0,M.jsx)(d.p,{value:p,onChange:e=>x(e.target.value),className:"bg-input","data-testid":"convert-client-name"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Client email"}),(0,M.jsx)(d.p,{type:"email",value:r,onChange:e=>m(e.target.value),placeholder:"[email protected]",className:"bg-input","data-testid":"convert-client-email"}),(0,M.jsx)("p",{className:"text-[11px] text-muted-foreground mt-1",children:"They'll log in via Google OAuth using this email address."})]}),(0,M.jsxs)("div",{className:"flex items-center gap-3 pt-1",children:[(0,M.jsx)(u.d,{checked:g,onCheckedChange:j,"data-testid":"convert-client-send-invite"}),(0,M.jsx)(o.J,{className:"text-sm",children:"Send invitation email"})]}),(0,M.jsxs)("div",{className:"flex justify-end gap-2 pt-2",children:[(0,M.jsx)(c.$,{variant:"ghost",onClick:s,disabled:v,children:"Cancel"}),(0,M.jsx)(c.$,{onClick:async()=>r.includes("@")?p.trim()?(b(!0),await l({email:r.trim().toLowerCase(),name:p.trim(),sendInvite:g}),void b(!1)):i.oR.error("Client name is required"):i.oR.error("A valid email is required"),disabled:v,className:"font-bold uppercase","data-testid":"convert-client-confirm",children:v?"Saving\u2026":"Save as Client"})]})]})]})})},H=e=>{let{row:t,onSaved:a,onCancel:s}=e;const[r,m]=(0,n.useState)(t.notes||""),[u,x]=(0,n.useState)((t.tags||[]).join(", ")),[h,g]=(0,n.useState)(t.outreach_email||""),[j,v]=(0,n.use
2State)(!1);return(0,M.jsxs)("div",{className:"space-y-4",children:[(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Outreach email"}),(0,M.jsx)(d.p,{type:"email",value:h,onChange:e=>g(e.target.value),placeholder:"[email protected]",className:"bg-input","data-testid":"marketing-edit-email"}),(0,M.jsx)("p",{className:"text-[11px] text-muted-foreground mt-1",children:'Saved here, used by the "Send Email" button. Leave empty to set on first send.'})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Notes"}),(0,M.jsx)(p.T,{rows:5,value:r,maxLength:5e3,onChange:e=>m(e.target.value),placeholder:"Internal notes \u2014 pitch context, decision-maker name, follow-up details\u2026",className:"bg-input","data-testid":"marketing-edit-notes"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{children:"Tags (comma-separated)"}),(0,M.jsx)(d.p,{value:u,onChange:e=>x(e.target.value),placeholder:"hot-lead, q2-campaign, follow-up",className:"bg-input","data-testid":"marketing-edit-tags"})]}),(0,M.jsx)("div",{className:"text-[11px] text-muted-foreground space-y-1",children:t.contact_log&&t.contact_log.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)("p",{className:"uppercase tracking-widest text-foreground",children:"Recent contact log:"}),(0,M.jsx)("ul",{className:"space-y-1 ml-2",children:t.contact_log.slice(-5).reverse().map((e,t)=>{var a;return(0,M.jsxs)("li",{className:"flex gap-2",children:[(0,M.jsx)("span",{className:"font-mono",children:null===(a=e.at)||void 0===a?void 0:a.slice(0,16).replace("T"," ")}),(0,M.jsxs)("span",{className:"uppercase",children:["[",e.channel,"]"]}),(0,M.jsx)("span",{children:e.note||"\u2014"})]},t)})})]})}),(0,M.jsxs)("div",{className:"flex justify-end gap-2 pt-2",children:[(0,M.jsx)(c.$,{variant:"ghost",onClick:s,disabled:j,children:"Cancel"}),(0,M.jsx)(c.$,{onClick:async()=>{v(!0);try{await l.A.put("".concat(V,"/api/admin/marketing/").concat(t.place_id),{notes:r,tags:u.split(",").map(e=>e.trim()).filter(Boolean),outreach_email:h.trim()||null},{withCredentials:!0}),i.oR.success("Saved"),a()}catch(n){var e,s;i.oR.error((null===(e=n.response)||void 0===e||null===(s=e.data)||void 0===s?void 0:s.detail)||"Failed to save")}finally{v(!1)}},disabled:j,className:"font-bold uppercase","data-testid":"marketing-edit-save",children:j?"Saving\u2026":"Save"})]})]})},K=()=>{const[e,t]=(0,n.useState)({mode:"text",query:"small businesses in Greenup KY",latitude:38.5779,longitude:-82.8918,radius_meters:25e3,included_type:"any",max_results:20}
2),[a,p]=(0,n.useState)(!1),[y,T]=(0,n.useState)([]),[E,L]=(0,n.useState)(0),[z,O]=(0,n.useState)(!0),[G,K]=(0,n.useState)("all"),[W,Y]=(0,n.useState)("all"),[Q,X]=(0,n.useState)(""),[ee,te]=(0,n.useState)(null),[ae,se]=(0,n.useState)("never"),[ne,le]=(0,n.useState)(null),[ie,re]=(0,n.useState)(!1),[ce,de]=(0,n.useState)(null),[oe,me]=(0,n.useState)(null),[ue,pe]=(0,n.useState)([]),xe=async()=>{O(!0);try{const e={limit:500};"all"!==G&&(e.filter=G),"all"!==W&&(e.contacted=W),Q.trim()&&(e.search=Q.trim());const t=await l.A.get("".concat(V,"/api/admin/marketing"),{withCredentials:!0,params:e});T(t.data.results||[]),L(t.data.total||0)}catch(e){i.oR.error("Failed to load businesses")}finally{O(!1)}};(0,n.useEffect)(()=>{xe()},[G,W]);const he=async e=>{try{const t=await l.A.get("".concat(V,"/api/admin/marketing/export/").concat(e),{withCredentials:!0,responseType:"blob",params:{filter:ae}}),a=window.URL.createObjectURL(new Blob([t.data])),s=document.createElement("a");s.href=a;const n=(new Date).toISOString().slice(0,10);s.setAttribute("download","marketing-".concat(ae,"-").concat(n,".").concat(e)),document.body.appendChild(s),s.click(),s.remove(),window.URL.revokeObjectURL(a),i.oR.success("Exported ".concat(e.toUpperCase()))}catch(s){var t,a;i.oR.error((null===(t=s.response)||void 0===t||null===(a=t.data)||void 0===a?void 0:a.detail)||"Export failed")}};return(0,M.jsxs)("div",{className:"space-y-4","data-testid":"admin-marketing-tab",children:[(0,M.jsxs)(r.Zp,{className:"p-5 border-border",children:[(0,M.jsx)("div",{className:"flex items-start justify-between gap-3 mb-4 flex-wrap",children:(0,M.jsxs)("div",{children:[(0,M.jsxs)("h3",{className:"font-bold uppercase tracking-tight flex items-center gap-2",children:[(0,M.jsx)(g.A,{className:"w-4 h-4 text-primary"}),"Prospect Search \u2014 Google Places"]}),(0,M.jsx)("p",{className:"text-xs text-muted-foreground mt-1",children:"Pull live business listings from Google. Results are saved to the CMS below \u2014 re-running the same search never duplicates a listing, and your contact history is preserved."})]})}),(0,M.jsxs)("form",{onSubmit:async t=>{var a;null===t||void 0===t||null===(a=t.preventDefault)||void 0===a||a.call(t),p(!0);try{var s,n,r;const t={mode:e.mode,max_results:e.max_results,excluded_place_ids:ue};if("text"===e.mode){if(!e.query.trim())return p(!1),i.oR.error("Enter a search query");t.query=e.query.trim(),e.latitude&&e.longitude&&(t.bias_lat=parseFloat(e.latitude),t.bias_lng=parseFloat(e.longitude),t.bias_radius_meters=parseFloat(e.radius_meters))}else t.latitude=parseFloat(e.latitude),t.longitude=parseFloat(e.longitude),t.radius_meters=parseFloat(e.radius_meters),e.included_type&&"any"!==e.included_type&&(t.included_types=[e.included_type]);const a=await l.A.post("".concat(V,"/api/admin/marketing/search"),t,{withCredentials:!0}),c=null!==(s=null!==(n=a.data.new_count)&&void 0!==n?n:a.data.count)&&void 0!==s?s:0,d=null!==(r=a.data.existing_count)&&void 0!==r?r:0,o=[...a.data.new_results||[],...a.data.existing_results||[]].map(e=>e.place_id).filter(Boolean);o.length&&pe(e=>Array.from(new Set([...e,...o]))),0===c&&0===d?i.oR.message("Google returned no more results \u2014 try tweaking the query, radius, or coordinates."):0===c?i.oR.message("No new businesses (".concat(d," already in CMS). Try widening the radius or a different query.")):i.oR.success("Added ".concat(c," new business").concat(1===c?"":"es").concat(d?" (".concat(d," already in CMS)"):"")),xe()}catch(o){var c,d;const e=(null===(c=o.response)||void 0===c||null===(d=c.data)||void 0===d?void 0:d.detail)||o.message;i.oR.error("Search failed: ".concat(e))}finally{p(!1)}},className:"space-y-4",children:[(0,M.jsxs)("div",{className:"flex items-center gap-3",children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Search mode"}),(0,M.jsxs)(x.l6,{value:e.mode,onValueChange:a=>t((0,s.A)((0,s.A)({},e),{},{mode:a})),children:[(0,M.jsx)(x.bq,{className:"bg-input w-[160px]","data-testid":"marketing-search-mode",children:(0,M.jsx)(x.yv,{})}),(0,M.jsxs)(x.gC,{children:[(0,M.jsx)(x.eb,{value:"text",children:"Text query"}),(0,M.jsx)(x.eb,{value:"nearby",children:"Nearby (lat/lng + radiu
2s)"})]})]})]}),"text"===e.mode?(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Search query"}),(0,M.jsx)(d.p,{value:e.query,onChange:a=>t((0,s.A)((0,s.A)({},e),{},{query:a.target.value})),placeholder:"e.g. dental clinics in Ashland KY",className:"bg-input","data-testid":"marketing-search-query"}),(0,M.jsx)("p",{className:"text-[11px] text-muted-foreground mt-1",children:"Optional location bias below \u2014 leave coords empty for global text search."})]}):(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Business type (optional)"}),(0,M.jsxs)(x.l6,{value:e.included_type,onValueChange:a=>t((0,s.A)((0,s.A)({},e),{},{included_type:a})),children:[(0,M.jsx)(x.bq,{className:"bg-input","data-testid":"marketing-search-type",children:(0,M.jsx)(x.yv,{placeholder:"Any type"})}),(0,M.jsxs)(x.gC,{className:"max-h-[260px]",children:[(0,M.jsx)(x.eb,{value:"any",children:"Any type"}),D.filter(e=>e).map(e=>(0,M.jsx)(x.eb,{value:e,children:e},e))]})]})]}),(0,M.jsxs)("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-3",children:[(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Latitude"}),(0,M.jsx)(d.p,{type:"number",step:"any",value:e.latitude,onChange:a=>t((0,s.A)((0,s.A)({},e),{},{latitude:a.target.value})),className:"bg-input","data-testid":"marketing-search-lat"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Longitude"}),(0,M.jsx)(d.p,{type:"number",step:"any",value:e.longitude,onChange:a=>t((0,s.A)((0,s.A)({},e),{},{longitude:a.target.value})),className:"bg-input","data-testid":"marketing-search-lng"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Radius (m)"}),(0,M.jsx)(d.p,{type:"number",value:e.radius_meters,onChange:a=>t((0,s.A)((0,s.A)({},e),{},{radius_meters:a.target.value})),className:"bg-input","data-testid":"marketing-search-radius"})]}),(0,M.jsxs)("div",{children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Max results"}),(0,M.jsx)(d.p,{type:"number",min:"1",max:"20",value:e.max_results,onChange:a=>t((0,s.A)((0,s.A)({},e),{},{max_results:a.target.value})),className:"bg-input","data-testid":"marketing-search-max"})]})]}),(0,M.jsxs)("div",{className:"flex items-center gap-2 flex-wrap",children:[(0,M.jsxs)(c.$,{type:"submit",disabled:a,className:"font-bold uppercase tracking-widest","data-testid":"marketing-run-search-btn",children:[a?(0,M.jsx)(j.A,{className:"w-4 h-4 mr-2 animate-spin"}):(0,M.jsx)(g.A,{className:"w-4 h-4 mr-2"}),a?"Searching\u2026":ue.length>0?"Find More":"Run Search"]}),ue.length>0&&(0,M.jsxs)(c.$,{type:"button",variant:"ghost",size:"sm",onClick:()=>pe([]),"data-testid":"marketing-reset-search-btn",children:["Reset session (",ue.length," seen)"]})]}),(0,M.jsx)("p",{className:"text-[11px] text-muted-foreground",children:'Google\'s free tier covers ~5K Places searches / month. Each call returns up to 20 listings \u2014 click "Find More" to ask Google for fresh results within the same parameters.'})]})]}),(0,M.jsxs)(r.Zp,{className:"p-4 border-border",children:[(0,M.jsxs)("div",{className:"flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3 flex-wrap",children:[(0,M.jsxs)("div",{className:"flex items-center gap-3 flex-wrap",children:[(0,M.jsx)(d.p,{value:Q,onChange:e=>X(e.target.value),onKeyDown:e=>{"Enter"===e.key&&xe()},placeholder:"Filter by name or address\u2026",className:"bg-input w-[260px]","data-testid":"marketing-cms-search"}),(0,M.jsx)(c.$,{variant:"outline",size:"sm",onClick:xe,children:"Apply"}),(0,M.jsxs)(x.l6,{value:G,onValueChange:K,children:[(0,M.jsx)(x.bq,{className:"bg-input w-[200px]","data-testid":"marketing-cms-filter",children:(0,M.jsx)(x.yv,{})}),(0,M.jsx)(x.gC,{children:Object.entries(U).map(e=>{let[t,a]=e;return(0,M.jsx)(x.eb,{value:t,children:a},t)})})]}),(0,M.jsxs)(x.l6,{value:W,onValueChange:Y,children:[(0,M.jsx)(x.bq,{className:"bg-input w-[160px]","data-testid":"marketing-cms-contacted",children:(0,M.jsx)(x.yv,{})}),(0,M.jsxs)(x.gC,{children:[(0,M.jsx)(x.eb,{value:"all",children:"All"}),(0,M.jsx)(x.eb,{value:"true",children:"Contacted"}),(0,M.jsx)(x.eb,{value:"false",children:"Not contacted"})]})]})]}),(0,M.jsxs)("div",{className:"flex items-center gap-2 flex-wrap",children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Export filter"}),(0,M.jsxs)(x.l6,{value:ae,onValueChange:se,children:[(0,M.jsx)(x.bq,{className:"bg-input w-[220px]","data-testid":"marketing-export-filter",children:(0,M.jsx)(x.yv,{})}),(0,M.jsxs)(x.gC,{children:[(0,M.jsx)(x.eb,{value:"never",children:"Never contacted"}),(0,M.jsx)(x.eb,{value:"12mo",children:"No contact in 12 months"}),(0,M.jsx)(x.eb,{value:"24mo",children:"No contact in 24 months"}),(0,M.jsx)(x.eb,{value:"all",children:"All businesses"})]})]}),(0,M.jsxs)(c.$,{variant:"outline",size:"sm",onClick:()=>
2he("csv"),"data-testid":"marketing-export-csv-btn",children:[(0,M.jsx)(v.A,{className:"w-3.5 h-3.5 mr-1.5"}),"CSV"]}),(0,M.jsxs)(c.$,{size:"sm",onClick:()=>he("xlsx"),"data-testid":"marketing-export-xlsx-btn",children:[(0,M.jsx)(v.A,{className:"w-3.5 h-3.5 mr-1.5"}),"Excel"]})]})]}),(0,M.jsxs)("p",{className:"text-[11px] text-muted-foreground mt-3",children:[y.length," of ",E," businesses shown."]}),(0,M.jsxs)("div",{className:"mt-4 pt-4 border-t border-border flex items-center gap-2 flex-wrap",children:[(0,M.jsx)(o.J,{className:"text-xs uppercase tracking-widest text-muted-foreground",children:"Bulk import:"}),(0,M.jsx)("input",{type:"file",accept:".csv",id:"marketing-csv-input",className:"hidden",onChange:async e=>{var t;const a=null===(t=e.target.files)||void 0===t?void 0:t[0];if(e.target.value="",!a)return;if(!a.name.toLowerCase().endsWith(".csv"))return i.oR.error("File must be a .csv");re(!0);const s=new FormData;s.append("file",a);try{const e=await l.A.post("".concat(V,"/api/admin/marketing/import-csv"),s,{withCredentials:!0,headers:{"Content-Type":"multipart/form-data"}});i.oR.success("Imported ".concat(e.data.created," new, updated ").concat(e.data.updated,", skipped ").concat(e.data.skipped)),xe()}catch(c){var n,r;i.oR.error((null===(n=c.response)||void 0===n||null===(r=n.data)||void 0===r?void 0:r.detail)||"Import failed")}finally{re(!1)}},"data-testid":"marketing-csv-input"}),(0,M.jsxs)(c.$,{size:"sm",variant:"outline",onClick:()=>document.getElementById("marketing-csv-input").click(),disabled:ie,"data-testid":"marketing-csv-import-btn",children:[(0,M.jsx)(b.A,{className:"w-3.5 h-3.5 mr-1.5"}),ie?"Importing\u2026":"Upload CSV"]}),(0,M.jsx)("span",{className:"text-[11px] text-muted-foreground",children:"Columns: name (required), address, phone, website, email, notes, tags"})]})]}),(0,M.jsx)(I,{exportFilter:ae}),z&&(0,M.jsx)(r.Zp,{className:"p-12 text-center border-border",children:(0,M.jsx)(j.A,{className:"w-8 h-8 animate-spin mx-auto text-muted-foreground"})}),!z&&0===y.length&&(0,M.jsxs)(r.Zp,{className:"p-12 text-center border-border",children:[(0,M.jsx)(g.A,{className:"w-10 h-10 mx-auto text-muted-foreground/50 mb-3"}),(0,M.jsx)("p",{className:"text-muted-foreground",children:"No businesses match this filter."}),(0,M.jsx)("p",{className:"text-xs text-muted-foreground mt-2",children:"Run a search above to populate the CMS."})]}),(0,M.jsx)("div",{className:"space-y-3",children:!z&&y.map(e=>(0,M.jsx)(r.Zp,{className:"p-4 border-border","data-testid":"marketing-row-".concat(e.place_id),children:(0,M.jsxs)("div",{className:"flex flex-col md:flex-row md:items-start justify-between gap-4",children:[(0,M.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,M.jsxs)("div",{className:"flex flex-wrap items-center gap-2 mb-2",children:[(0,M.jsx)("h4",{className:"font-bold text-base",children:e.name}),e.client_user_id?(0,M.jsxs)(m.E,{variant:"outline",className:"text-[10px] uppercase tracking-widest text-primary border-primary/60 bg-primary/10 cursor-pointer",onClick:()=>me(e.client_user_id),"data-testid":"marketing-client-badge-".concat(e.place_id),children:[(0,M.jsx)(f.A,{className:"w-3 h-3 mr-1 inline"}),"Client"]}):e.contacted?(0,M.jsxs)(m.E,{variant:"outline",className:"text-[10px] uppercase tracking-widest text-primary border-primary/50",children:[(0,M.jsx)(N.A,{className:"w-3 h-3 mr-1 inline"}),"Contacted ",e.contacted_count>1?"".concat(e.contacted_count,"\xd7"):""]}):(0,M.jsx)(m.E,{variant:"outline",className:"text-[10px] uppercase tracking-widest text-muted-foreground",children:"Not contacted"}),e.rating&&(0,M.jsxs)(m.E,{variant:"outline",className:"text-[10px] text-amber-400 border-amber-500/30",children:[(0,M.jsx)(k,{className:"w-3 h-3 mr-1 inline fill-amber-400"}),e.rating," (",e.user_rating_count||0,")"]}),(e.types||[]).slice(0,2).map(e=>(0,M.jsx)(m.E,{variant:"outline",className:"text-[10px] capitalize",children:e.replace(/_/g," ")},e))]}),e.formatted_address&&(0,M.jsxs)("p",{className:"text-xs text-muted-foreground flex items-center gap-1.5 mb-1",children:[(0,M.jsx)(w.A,{className:"w-3 h-3 shrink-0"}),e.formatted_address]}),(0,M.jsxs)("div",{className:"flex flex-wrap gap-3 text-xs text-muted-foreground",children:[e.phone_number&&(0,M.jsxs)("span",{className:"inline-flex items-center gap-1.5",children:[(0,M.jsx)(_.A,{className:"w-3 h-3"}),e.phone_number]}),e.website&&(0,M.jsxs)("a",{href:e.website,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 text-primary hover:underline",children:[(0,M.jsx)(C.A,{className:"w-3 h-3"}),e.website.replace(/^https?:\/\//,"").split("/")[0]]}),e.google_maps_uri&&(0,M.jsxs)("a",{href:e.google_maps_uri,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 hover:underline",children:[(0,M.jsx)(S.A,{className:"w-3 h-3"}),"Google Maps"]}),e.last_contacted_at&&(0,M.jsxs)("span",{children:["Last contacted: ",(0,J.GP)(new Date(e.last_contacted_at),"MMM dd, yyyy")]})]}),e.notes&&(0,M.jsx)("p",{className:"mt-2 text-xs italic text-muted-foreground border-l-2 border-border pl-2",children:e.notes})]}),(0,M.jsxs)("div",{className:"flex flex-row md:flex-col items-end gap-2 shrink-0",children:[(0,M.jsxs)("div",{className:"flex items-center gap-2",children:[(0,M.jsx)(o.J,{className:"text-[10px] uppercase text-muted-foreground",children:"Contacted"}),(0,M.jsx)(u.d,{checked:!!e.contacted,onCheckedChange:()=>(async e=>{try{await l.A.put("".concat(V,"/api/admin/marketing/").concat(e.place_id),{contacted:!e.contacted},{withCredentials:!0}),xe()}catch(t){i.oR.error("Failed to update")}})(e),"data-testid":"marketing-contacted-toggle-".concat(e.place_id)})]}),(0,M.jsxs)("div",{className:"flex items-center gap-1 flex-wrap justify-end",children:[e.client_user_id?(0,M.jsxs)(c.$,{size:"sm",variant:"outline",onClick:()=>
2me(e.client_user_id),title:"Open client profile",className:"border-primary/60 text-primary hover:bg-primary/10","data-testid":"marketing-profile-".concat(e.place_id),children:[(0,M.jsx)(f.A,{className:"w-3.5 h-3.5 mr-1"}),"Profile"]}):(0,M.jsxs)(c.$,{size:"sm",variant:"outline",onClick:()=>de(e),title:"Save as client",className:"border-primary/60 text-primary hover:bg-primary/10","data-testid":"marketing-save-client-".concat(e.place_id),children:[(0,M.jsx)(A.A,{className:"w-3.5 h-3.5 mr-1"}),"Save as Client"]}),(0,M.jsx)(c.$,{size:"sm",variant:"outline",onClick:()=>le(e),title:"Send email","data-testid":"marketing-send-".concat(e.place_id),children:(0,M.jsx)(R.A,{className:"w-3.5 h-3.5"})}),(0,M.jsx)(c.$,{size:"sm",variant:"outline",onClick:()=>(async e=>{const t=window.prompt('Log a contact for "'.concat(e.name,'". Optional note:'));if(null!==t)try{await l.A.post("".concat(V,"/api/admin/marketing/").concat(e.place_id,"/log-contact"),{channel:"manual",note:t||""},{withCredentials:!0}),i.oR.success("Contact logged"),xe()}catch(a){i.oR.error("Failed to log contact")}})(e),title:"Log a contact","data-testid":"marketing-log-".concat(e.place_id),children:(0,M.jsx)($,{className:"w-3.5 h-3.5"})}),(0,M.jsx)(c.$,{size:"sm",variant:"outline",onClick:()=>te(e),title:"Edit notes","data-testid":"marketing-edit-".concat(e.place_id),children:(0,M.jsx)(q.A,{className:"w-3.5 h-3.5"})}),(0,M.jsx)(c.$,{size:"sm",variant:"ghost",onClick:()=>(async e=>{if(window.confirm('Remove "'.concat(e.name,'" from the CMS? Search history is gone too.')))try{await l.A.delete("".concat(V,"/api/admin/marketing/").concat(e.place_id),{withCredentials:!0}),i.oR.success("Removed"),xe()}catch(t){i.oR.error("Failed to delete")}})(e),className:"text-destructive hover:text-destructive","data-testid":"marketing-delete-".concat(e.place_id),children:(0,M.jsx)(F.A,{className:"w-3.5 h-3.5"})})]})]})]})},e.place_id))}),(0,M.jsx)(h.lG,{open:!!ee,onOpenChange:e=>!e&&te(null),children:(0,M.jsxs)(h.Cf,{className:"bg-card border-border max-w-lg","data-testid":"marketing-edit-dialog",children:[(0,M.jsx)(h.c7,{children:(0,M.jsx)(h.L3,{className:"text-xl font-bold uppercase",children:null===ee||void 0===ee?void 0:ee.name})}),ee&&(0,M.jsx)(H,{row:ee,onSaved:()=>{te(null),xe()},onCancel:()=>te(null)})]})}),(0,M.jsx)(P,{open:!!ne,onClose:()=>le(null),business:ne,onSent:xe}),(0,M.jsx)(Z,{open:!!ce,business:ce,onCancel:()=>de(null),onConfirm:e=>(async(e,t)=>{let{email:a,name:s,sendInvite:n}=t;try{const t=await l.A.post("".concat(V,"/api/admin/marketing/").concat(e.place_id,"/convert-to-client"),{email:a,name:s,send_invite:n},{withCredentials:!0});i.oR.success(t.data.invitation_sent?"Saved ".concat(s," as client \u2014 invitation sent"):"Saved ".concat(s," as client")),de(null),xe()}catch(d){var r,c;i.oR.error((null===(r=d.response)||void 0===r||null===(c=r.data)||void 0===c?void 0:c.detail)||"Failed to save as client")}})(ce,e)}),(0,M.jsx)(B.A,{userId:oe,open:!!oe,onClose:()=>me(null)})]})}},9292(e,t,a){a.d(t,{A:()=>s});const s=(0,a(7784).A)("search",[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]])}}]);
3//# sourceMappingURL=737.9723cd4f.chunk.js.map

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.