PageSourceSearch

https://taprecon.com/assets/Rules-CND3WRnq.js

js taprecon.com collected 2026-09-24 14:18:52 UTC 16,127 bytes, 21 lines download raw bytes

1import{c as A,v as X,r as n,j as e,m as Q,Q as I,Z as F,B as i,G as p,f as d,U as K,V as Y,W as O,X as W,I as C,h as U,Y as $,l as J}from"./index-CqCVJLCu.js";import{u as ee}from"./useRules-DYmdU6Kr.js";import{C as E,d as P,a as se,b as te}from"./card-DjodasfD.js";import{S as ae}from"./switch-CzU3d2_w.js";import{D as re,b as ne,c as ie,d as le,e as oe}from"./dialog-Dq_gn5j8.js";import{A as ce,a as de,b as me,c as xe,d as he,e as ue,f as pe,g as ge,h as je}from"./alert-dialog-9j9aY7rI.js";import{P as z}from"./plus-CjiVZUs9.js";import{T as fe}from"./trash-2-CaTO9qu7.js";import{I as ye}from"./info-Haj_qLSx.js";import"./useMutation-DFPJoyc2.js";import"./index-BnMJcl6T.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 Ne=A("Droplets",[["path",{d:"M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z",key:"1ptgy4"}],["path",{d:"M12.56 6.6A10.97 10.97 0 0 0 14 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 0 1-11.91 4.97",key:"1sl1rz"}]]);/**
7 * @license lucide-react v0.462.0 - ISC
8 *
9 * This source code is licensed under the ISC license.
10 * See the LICENSE file in the root directory of this source tree.
11 */const ve=A("Flame",[["path",{d:"M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z",key:"96xj49"}]]);/**
12 * @license lucide-react v0.462.0 - ISC
13 *
14 * This source code is licensed under the ISC license.
15 * See the LICENSE file in the root directory of this source tree.
16 */const be=A("Layers",[["path",{d:"m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z",key:"8b97xw"}],["path",{d:"m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65",key:"dd6zsq"}],["path",{d:"m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65",key:"ep9fru"}]]);/**
17 * @license lucide-react v0.462.0 - ISC
18 *
19 * This source code is licensed under the ISC license.
20 * See the LICENSE file in the root directory of this source tree.
21 */const we=A("Pencil",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]),V={hvac:{label:"HVAC",icon:ve,keywords:["AC not cooling","AC stopped working","no cold air","AC broken","need AC repair","furnace not heating","no heat","heater not working","need HVAC recommendation","HVAC company near","water leaking from AC unit","AC making loud noise","AC unit replacement quote","ductwork installation","new AC install","emergency HVAC","heat pump not working"],exclude_terms:["DIY","hiring","apprentice","HVAC school","training program","battery"],lead_threshold:65,description:"Best for residential HVAC service and install businesses."},plumbing:{label:"Plumbing",icon:Ne,keywords:["need a plumber","plumber recommendation","water heater not working","no hot water","water heater leaking","toilet leaking","pipe burst","sewer backup","main line clog","clogged drain wont clear","slab leak","garbage disposal broken","emergency plumber","tankless water heater install","repiping quote","sump pump not working"],exclude_terms:["DIY tutorial","hiring plumber","apprentice","plumbing school","sale"],lead_threshold:65,description:"Best for residential plumbing service, water heater, and drain businesses."},electrical:{label:"Electrical",icon:F,keywords:["need an electrician","electrician recommendation","breaker keeps tripping","no power in one room","outlet stopped working","sparking outlet","electrical panel upgrade quote","EV charger install","level 2 charger install","hot tub wiring","generator install quote","GFCI keeps tripping","lights flickering","buzzing outlet","transfer switch install","dedicated circuit for","emergency electrician"],exclude_terms:["DIY","hiring electrician","apprentice","electrical school","training","sale","battery","power strip"],lead_threshold:65,description:"Best for residential electrical service, panel, and EV-charger businesses."}};function M({keywords:r,onChange:g}){const[l,o]=n.useState(""),j=()=>{const a=l.trim();a&&!r.includes(a)&&g([...r,a]),o("")},D=a=>{g(r.filter(T=>
21T!==a))};return e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx(C,{placeholder:"Type a keyword and press Enter",value:l,onChange:a=>o(a.target.value),onKeyDown:a=>{a.key==="Enter"&&(a.preventDefault(),j())}}),e.jsx(i,{type:"button",variant:"outline",onClick:j,disabled:!l.trim(),children:"Add"})]}),r.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1.5",children:r.map(a=>e.jsxs(p,{variant:"secondary",className:"gap-1 pr-1 cursor-pointer hover:bg-destructive/20",onClick:()=>D(a),children:[a,e.jsx($,{className:"h-3 w-3"})]},a))})]})}function Le(){const{rules:r,isLoading:g,createRule:l,updateRule:o,toggleRule:j,deleteRule:D}=ee(),{workspaceId:a}=X(),[T,R]=n.useState(null),[B,m]=n.useState(!1),[x,L]=n.useState(null),[h,f]=n.useState(""),[c,y]=n.useState([]),[N,v]=n.useState([]),[b,w]=n.useState(70),[_,S]=n.useState(0),k=()=>{f(""),y([]),v([]),w(70),S(0),L(null)},H=()=>{k(),R(a),m(!0)},q=s=>{f(s.name),y(s.keywords||[]),v(s.exclude_terms||[]),w(s.lead_threshold??70),S(s.min_intent_score??0),L(s.id),R(a),m(!0)},Z=s=>{const t=V[s];t&&(f(t.label+" Lead Detection"),y(Array.from(new Set([...c,...t.keywords]))),v(Array.from(new Set([...N,...t.exclude_terms]))),w(t.lead_threshold),J.success(`Loaded ${t.label} example — you can edit anything before saving.`))},G=()=>{!h.trim()||c.length===0||(x?o.mutate({id:x,name:h.trim(),keywords:c,exclude_terms:N,lead_threshold:b,min_intent_score:_}):l.mutate({name:h.trim(),keywords:c,exclude_terms:N,lead_threshold:b,min_intent_score:_,workspace_id_override:T??void 0}),m(!1),k())};return g?e.jsxs("div",{className:"space-y-6",children:[e.jsx("h1",{className:"text-lg sm:text-xl md:text-2xl font-bold",children:"Tracking Rules"}),e.jsx("div",{className:"grid gap-4 md:grid-cols-2",children:[1,2].map(s=>e.jsx(Q,{className:"h-40"},s))})]}):e.jsxs("div",{className:"space-y-6",children:[e.jsx(E,{className:"border-primary/30 bg-primary/5",children:e.jsx(P,{className:"p-4 sm:p-5 space-y-3",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary",children:e.jsx(I,{className:"h-5 w-5"})}),e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsx("p",{className:"font-medium text-foreground",children:'Tracking Rules tell TAPrecon what a "real lead" looks like for your business.'}),e.jsxs("p",{className:"text-muted-foreground",children:["Your ",e.jsx("strong",{className:"text-foreground",children:"Sources"})," (on the Leads page) decide"," ",e.jsx("em",{children:"where"})," to look — subreddits, Facebook groups. Your"," ",e.jsx("strong",{className:"text-foreground",children:"Rules"})," here decide"," ",e.jsx("em",{children:"what counts"})," as a lead vs. noise. Keywords, exclusions, and thresholds apply"," ",e.jsx("strong",{className:"text-foreground",children:"globally across every source you've connected"})," ","— not per-source."]}),e.jsxs("div",{className:"grid gap-2 sm:grid-cols-3 pt-1",children:[e.jsxs("div",{className:"rounded-md bg-background/60 p-2.5 text-xs",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-1.5 font-medium text-foreground",children:[e.jsx(F,{className:"h-3.5 w-3.5 text-primary"})," Keywords"]}),e.jsx("p",{className:"text-muted-foreground",children:'Phrases customers actually type. "AC not cooling", "need an electrician near me".'})]}),e.jsxs("div",{className:"rounded-md bg-background/60 p-2.5 text-xs",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-1.5 font-medium text-foreground",children:[e.jsx(be,{className:"h-3.5 w-3.5 text-primary"})," Exclusions"]}),e.jsx("p",{className:"text-muted-foreground",children:`Words that mean this ISN'T a lead. "DIY", "hiring", "apprentice", "sale".`})]}),e.jsxs("div",{className:"rounded-md bg-background/60 p-2.5 text-xs",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-1.5 font-medium text-foreground",children:[e.jsx(I,{className:"h-3.5 w-3.5 text-primary"})," Threshold"]}),e.jsx("p",{className:"text-muted-foreground",children:"Minimum AI intent score to become a lead. 65 is a good starting point."})]})]})]})]})})}),e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl sm:text-2xl font-bold",children:"Tracking Rules"}),e.jsx("p",{className:"text-muted-foreground text-sm mt-1",children:"Define keywords the AI uses to find leads in your monitored sources."})]}),e.jsxs(i,{onClick:H,className:"self-start sm:self-auto",children:[e.jsx(z,{className:"h-4 w-4 mr-2"})," New Rule"]})]}),r.length===0?e.jsx(E,{className:"border-dashed",children:e.jsxs(P,{className:"flex flex-col items-center justify-center py-6 sm:py-10 md:py-12 text-center",children:[e.jsx(I,{className:"h-10 w-10 text-muted-foreground mb-3"}),e.jsx("h3",{className:"font-semibold text-lg mb-1",children:"No tracking rules yet"}),e.jsx("p",{className:"text-muted-foreground text-sm max-w-md mb-4",children:"Create your first rule with trade-specific keywords so TAPrecon knows what leads to look for."}),e.jsxs(i,{onClick:H,children:[e.jsx(z,{className:"h-4 w-4 mr-2"})," Create Your First Rule"]})]})}):e.jsx("div",{className:"grid gap-4 grid-cols-1 lg:grid-cols-2",children:r.map(s=>e.jsxs(E,{className:"border-border/50 bg-card min-w-0 overflow-hidden",children:[e.jsxs(se,{className:"flex flex-row items-start justify-between pb-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(te,{className:"text-base truncate",children:s.name}),e.jsx(p,{variant:s.is_active?"default":"secondary",className:"shrink-0 text-xs",children:s.is_active?"Active":"Paused"})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Lead threshold: ",s.lead_threshold??70,"+ intent score"]})]}),e.jsx(ae,{checked:s.is_active,onCheckedChange:t=>j.mutate({id:s.id,is_active:t})})]}),e.jsxs(P,{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsxs("p",{className:"text-xs font-medium text-muted-foreground mb-1.5",children:["Keywords (",(s.keywords||[]).length,")"]}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[(s.keywords||[]).slice(0,8).map(t=>e.jsx(p,{variant:"outline",className:"text-xs",children:t},t)),(s.keywords||[]).length>8&&e.jsxs(p,{variant:"outline",className:"text-xs text-muted-foreground",children:["+",(s.keywords||[]).length-8," more"]})]})]}),(s.exclude_terms||[]).length>0&&e.jsxs("div",{children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground mb-1.5",children:"Exclude"}),e.jsx("div",{className:"flex flex-wrap gap-1",children:(s.exclude_terms||[]).map(t=>e.jsx(p,{variant:"destructive",className:"text-xs opacity-70",children:t},t))})]}),e.jsxs("div",{className:"flex gap-2 pt-1",children:[e.jsxs(i,{variant:"outline",size:"sm",onClick:()=>q(s),children:[e.jsx(we,{className:"h-3 w-3 mr-1"})," Edit"]}),e.jsxs(ce,{children:[e.jsx(de,{asChild:!0,children:e.jsxs(i,{variant:"outline",size:"sm",className:"text-destructive hover:text-destructive",children:[e.jsx(fe,{className:"h-3 w-3 mr-1"})," Delete"]})}),e.jsxs(me,{children:[e.jsxs(xe,{children:[e.jsxs(he,{children:['Delete "',s.name,'"?']}),e.jsx(ue,{children:"This removes the rule permanently. Existing leads won't be deleted."})]}),e.jsxs(pe,{children:[e.jsx(ge,{children:"Cancel"}),e.jsx(je,{onClick:()=>D.mutate(s.id),children:"Delete"})]})]})]})]})]})]},s.id))}),e.jsx(re,{open:B,onOpenChange:s=>{m(s),s||k()},children:e.jsxs(ne,{className:"max-w-lg max-h-[85vh] overflow-y-auto",children:[e.jsx(ie,{children:e.jsx(le,{children:x?"Edit Rule":"Create Tracking Rule"})}),e.jsxs("div",{className:"space-y-5 py-2",children:[!x&&e.jsxs("div",{children:[e.jsx(d,{className:"text-sm",children:"Start from an example"}),e.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:Object.entries(V).map(([s,t])=>e.jsx(K,{delayDuration:200,children:e.jsxs(Y,{children:[e.jsx(O,{asChild:!0,children:e.jsxs(i,{variant:"outline",size:"sm",className:"gap-1.5",onClick:()=>Z(s),children:[e.jsx(t.icon,{className:"h-3.5 w-3.5"}),t.label]})}),e.jsx(W,{side:"top",className:"max-w-xs text-sm",children:e.jsx("p",{children:t.description})})]})},s))}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1.5",children:"Loads a tested rule for that trade — keywords, exclusions, and a threshold. Edit anything before saving."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(d,{children:"Rule Name"}),e.jsx(u,{text:"A short name so you remember what this rule does. Only you see this — customers never do."})]}),e.jsx(C,{placeholder:"e.g. HVAC Lead Detection",value:h,onChange:s=>
21f(s.target.value)})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(d,{children:"Keywords to Monitor"}),e.jsx(u,{text:"Phrases the AI looks for in posts. Type ONE keyword or phrase per entry (e.g. 'AC not cooling'). These apply to EVERY source you've connected — not just one. More specific = better."})]}),e.jsx(M,{keywords:c,onChange:y})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(d,{children:"Exclude Terms (optional)"}),e.jsx(u,{text:"Words that mean a post is NOT a lead — job seekers, hobbyists, sales listings. TAPrecon skips any post containing these terms, no matter how well it matches your keywords."})]}),e.jsx(M,{keywords:N,onChange:v}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Posts containing these terms will be skipped even if they match keywords."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(d,{children:"Lead Threshold (intent score)"}),e.jsx(u,{text:"How confident TAPrecon has to be before turning a post into a lead. 0 = every match. 100 = only dead-certain buying intent. 65 is a good default for service businesses."})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(C,{type:"number",min:0,max:100,value:b,onChange:s=>w(Number(s.target.value)),className:"w-24"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:["Posts scoring ",b,"+ become leads automatically"]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(d,{children:"Minimum Intent Score"}),e.jsx(u,{text:"Posts scoring below this number are hidden entirely — they won't even show up in your Scanned Posts list. Set to 0 to see everything the AI looked at."})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(C,{type:"number",min:0,max:100,value:_,onChange:s=>S(Number(s.target.value)),className:"w-24"}),e.jsx("span",{className:"text-sm text-muted-foreground",children:"Ignore posts below this score entirely"})]})]})]}),e.jsxs(oe,{children:[e.jsx(i,{variant:"outline",onClick:()=>{m(!1),k()},children:"Cancel"}),e.jsxs(i,{onClick:G,disabled:!h.trim()||c.length===0||l.isPending||o.isPending,children:[(l.isPending||o.isPending)&&e.jsx(U,{className:"h-4 w-4 animate-spin mr-2"}),x?"Save Changes":"Create Rule"]})]})]})})]})}function u({text:r}){return e.jsx(K,{delayDuration:200,children:e.jsxs(Y,{children:[e.jsx(O,{asChild:!0,children:e.jsx("button",{type:"button",className:"inline-flex items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring","aria-label":"More info",children:e.jsx(ye,{className:"h-3.5 w-3.5"})})}),e.jsx(W,{side:"top",className:"max-w-xs text-sm",children:e.jsx("p",{children:r})})]})})}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.