PageSourceSearch

https://www.fortmcmurrayelectrician.ca/assets/SEOTagAudit-BUTuFsS9.js

js fortmcmurrayelectrician.ca collected 2026-10-07 09:49:26 UTC 15,201 bytes, 3 lines download raw bytes

1import{r as N,j as e}from"./index-C6ghbvAw.js";import{C as y,b as M,c as H,d as U,a as B}from"./card-DcpNRYUu.js";import{B as R}from"./button-BbS7p2-k.js";import{B as E}from"./badge-BFUr7P7F.js";import{P as z}from"./progress-UloT-BDg.js";import{S as V}from"./admin.index-EM_hIW-h.js";import{E as W}from"./jspdf.es.min-BuKZbkdX.js";import{S as G}from"./shield-check-BTMJKFoL.js";import{D as _}from"./download-Dkz6mz4y.js";import{F as J}from"./sparkles-aNfXL2wy.js";import{R as K}from"./refresh-cw-BMbe_Ahh.js";import{C as Y}from"./circle-check-big-CytuKn4U.js";import{T as X}from"./triangle-alert-DqOy4Ngi.js";import{C as q}from"./circle-x-Br9rSQpr.js";import"./index-C2P2Lrb-.js";import"./useQuery-vdPRfJTf.js";import"./use-toast-C3nhwJwR.js";import"./select-BFGQXtCb.js";import"./index-C0pbmnxW.js";import"./index-BHqJpBG2.js";import"./index-DHsQl3TH.js";import"./index-C-eifxmw.js";import"./chevron-down-lfBaL0Tq.js";import"./createLucideIcon-Dy-MC8t5.js";import"./check-Rn0oPDsL.js";import"./table-Dmh-JJu7.js";import"./tabs-DLjdEhAu.js";import"./input-Cbwh2FhS.js";import"./label-tIvJrmCc.js";import"./textarea-8GBgRy3q.js";import"./seo-image-helpers-DB_7kWdL.js";import"./sun-b-7CMHGl.js";import"./zap-DES_77W2.js";import"./building-BzFHRHxk.js";import"./battery-DixZPe70.js";import"./plug-DRnWGUIB.js";import"./bot-D-llnRl1.js";import"./link-2-qfFixvPv.js";import"./camera-CRVrnscP.js";import"./upload-IMMz7Q36.js";import"./star-BYkhXJgt.js";import"./message-circle-question-mark-DwHm2OeP.js";import"./linkedin-BEoJGbsh.js";import"./search-tVy8geSf.js";import"./mouse-pointer-2-C1mBXL-P.js";import"./calculator-Dv3OzH7F.js";import"./phone-CUUs3bXf.js";import"./clock-C4VYBqaB.js";import"./loader-circle-BDyB7zlj.js";import"./copy-CICM1-RE.js";import"./external-link-DXoZV9ic.js";const w=[{path:"/",name:"Home",kind:"public"},{path:"/about",name:"About",kind:"public"},{path:"/contact",name:"Contact",kind:"public"},{path:"/pricing",name:"Pricing",kind:"public"},{path:"/blog",name:"Blog",kind:"public"},{path:"/our-work",name:"Our Work",kind:"public"},{path:"/service-areas",name:"Service Areas",kind:"public"},{path:"/sitemap",name:"Sitemap",kind:"public"},{path:"/book-appointment",name:"Book Appointment",kind:"public"},{path:"/panel-upgrade-order",name:"Panel Upgrade Order",kind:"public"},{path:"/new-construction-order",name:"New Construction Order",kind:"public"},{path:"/permit-application",name:"Permit Application",kind:"public"},{path:"/ev-charger-installation",name:"EV Charger Installation",kind:"public"},{path:"/solar",name:"Solar Installation",kind:"public"},{path:"/home-electrical-repair",name:"Home Electrical Repair",kind:"public"},{path:"/electrical-panel-upgrade",name:"Panel Upgrade",kind:"public"},{path:"/home-rewire",name:"Home Rewire",kind:"public"},{path:"/generator-installation",name:"Generator Installation",kind:"public"},{path:"/smart-home-installation",name:"Smart Home Installation",kind:"public"},{path:"/electrical-inspection",name:"Electrical Inspection",kind:"public"},{path:"/commercial",name:"Commercial Electrical",kind:"public"},{path:"/industrial-subcontractor",name:"Industrial Subcontractor",kind:"public"},{path:"/restaurant-electrical",name:"Restaurant Electrical",kind:"public"},{path:"/retail-electrical",name:"Retail Electrical",kind:"public"},{path:"/dental-clinic-electrical",name:"Dental Clinic Electrical",kind:"public"},{path:"/privacy-policy",name:"Privacy Policy",kind:"public"},{path:"/terms-of-service",name:"Terms of Service",kind:"public"},{path:"/admin",name:"Admin Dashboard",kind:"utility"},{path:"/admin-login",name:"Admin Login",kind:"utility"},{path:"/seo-tools",name:"SEO Tools",kind:"utility"},{path:"/newsletter-confirm",name:"Newsletter Confirm",kind:"utility"},{path:"/newsletter-unsubscribe",name:"Newsletter Unsubscribe",kind:"utility"},{path:"/review-thank-you",name:"Review Thank You",kind:"utility"}],O="https://www.fortmcmurrayelectrician.ca",Q=(s,r,d,m)=>{const a=[];return s.kind==="public"?(r||a.push(`Add <link rel="canonical" href="${O}${s.path}" /> inside <Helmet>.`),m&&a.push('Remove the robots noindex directive — set <meta name="robots" content="index, follow" /> instead.')):(m||a.push('Add <meta name="robots" content="noindex, nofollow" /> inside <Helmet> to keep this utility page out of search results.'),!r&&m&&a.push(`Optional: add a canonical tag pointing to ${O}${s.path} for consistency.`)),d&&/noindex/i.test(d)&&/,?\s*follow/i.test(d)===!1&&/nofollow/i.test(d)===!1&&s.kind==="utility"&&a.push('Robots tag should also include "nofollow" for utility pages.'),a},S="seo-tag-audit-cache",$=2,Z=s=>{let r;try{r=JSON.parse(s)}catch{return null}if(!r||typeof r!="object"||!Array.isArray(r.rows))return null;let d=typeof r.version=="number"?r.version:1,m=r.rows;return d<2&&(m=m.map(a=>({path:a.path??"",name:a.name??a.path??"",kind:a.kind==="utility"?"utility":"public",canonical:a.canonical??null,robots:a.robots??null,hasNoindex:!!a.hasNoindex,status:a.status??"fail",issues:Array.isArray(a.issues)?a.issues:[],suggestions:Array.isArray(a.suggestions)?a.suggestions:[]})),d=2),{version:$,lastRun:typeof r.lastRun=="string"?r.lastRun:null,rows:m}},ee=(s,r)=>{const d=r.match(/<link[^>
1]*rel=["']canonical["'][^>]*href=["']([^"']+)["']/i)||r.match(/<link[^>]*href=["']([^"']+)["'][^>]*rel=["']canonical["']/i),m=d?d[1].trim():null,a=r.match(/<meta[^>]*name=["']robots["'][^>]*content=["']([^"']+)["']/i)||r.match(/<meta[^>]*content=["']([^"']+)["'][^>]*name=["']robots["']/i),b=a?a[1].trim():null,h=!!b&&/noindex/i.test(b),f=[];s.kind==="public"?(m||f.push("Missing canonical tag"),h&&f.push("Public page is set to noindex")):h||f.push("Utility page missing noindex");let j="pass";return f.some(o=>o.includes("Missing canonical")||o.includes("missing noindex")||o.includes("set to noindex"))?j="fail":f.length&&(j="warning"),{path:s.path,name:s.name,kind:s.kind,canonical:m,robots:b,hasNoindex:h,status:j,issues:f,suggestions:Q(s,m,b,h)}},Qe=()=>{const[s,r]=N.useState([]),[d,m]=N.useState(!1),[a,b]=N.useState(0),[h,f]=N.useState(null);N.useEffect(()=>{try{const t=localStorage.getItem(S);if(t){const c=Z(t);if(c){r(c.rows),f(c.lastRun),c.version;try{localStorage.setItem(S,JSON.stringify(c))}catch{}}else localStorage.removeItem(S)}}catch{}},[]);const j=N.useCallback(async()=>{m(!0),b(0);const t=[];for(let u=0;u<w.length;u++){const i=w[u];try{const x=await(await fetch(i.path,{headers:{"Cache-Control":"no-cache"}})).text();t.push(ee(i,x))}catch{t.push({path:i.path,name:i.name,kind:i.kind,canonical:null,robots:null,hasNoindex:!1,status:"fail",issues:["Failed to fetch route"],suggestions:["Verify the route exists and is reachable; re-run the audit."]})}b(Math.round((u+1)/w.length*100))}const c=new Date().toISOString();r(t),f(c);try{localStorage.setItem(S,JSON.stringify({version:$,rows:t,lastRun:c}))}catch{}m(!1)},[]);N.useEffect(()=>{s.length===0&&!d&&j();const t=setInterval(()=>{d||j()},300*1e3);return()=>clearInterval(t)},[]);const o={total:s.length,pass:s.filter(t=>t.status==="pass").length,warning:s.filter(t=>t.status==="warning").length,fail:s.filter(t=>t.status==="fail").length,missingCanonical:s.filter(t=>t.kind==="public"&&!t.canonical).length,missingNoindex:s.filter(t=>t.kind==="utility"&&!t.hasNoindex).length},v=s.length?Math.round(o.pass/s.length*100):0,I=({status:t})=>t==="pass"?e.jsx(Y,{className:"h-4 w-4 text-green-500"}):t==="warning"?e.jsx(X,{className:"h-4 w-4 text-yellow-500"}):e.jsx(q,{className:"h-4 w-4 text-red-500"}),T=(t,c,u)=>{const i=t instanceof Blob?t:new Blob([t],{type:u}),n=URL.createObjectURL(i),x=document.createElement("a");x.href=n,x.download=c,document.body.appendChild(x),x.click(),document.body.removeChild(x),URL.revokeObjectURL(n)},P=()=>{if(!s.length)return;const t=l=>`"${(l??"").replace(/"/g,'""')}"`,c=new Date().toLocaleString(),u=s.filter(l=>l.kind==="public").length,i=s.filter(l=>l.kind==="utility").length,n=[];n.push("SEO Tag Audit Report"),n.push(`Generated,${t(c)}`),n.push(`Last Scan,${t(h?new Date(h).toLocaleString():"N/A")}`),n.push(`Compliance Score,${v}%`),n.push(`Total Routes,${o.total}`),n.push(`Public Routes,${u}`),n.push(`Utility Routes,${i}`),n.push(`Passing,${o.pass}`),n.push(`Warnings,${o.warning}`),n.push(`Failures,${o.fail}`),n.push(`Missing Canonical,${o.missingCanonical}`),n.push(`Missing Noindex,${o.missingNoindex}`),n.push("");const x=["Route Name","Path","Type","Status","Canonical","Robots","Issues","Suggested Fix"];
1n.push(x.join(",")),s.forEach(l=>{n.push([t(l.name),t(l.path),t(l.kind),t(l.status),t(l.canonical||""),t(l.robots||""),t(l.issues.join("; ")),t(l.suggestions.join(" | "))].join(","))});const g=new Date().toISOString().split("T")[0];T(n.join(`
2`),`seo-tag-audit-${g}.csv`,"text/csv")},F=()=>{if(!s.length)return;const t=new W({orientation:"landscape",unit:"pt",format:"letter"}),c=t.internal.pageSize.getWidth(),u=t.internal.pageSize.getHeight();let i=40;const n=s.filter(p=>p.kind==="public").length,x=s.filter(p=>p.kind==="utility").length;t.setFontSize(16),t.text("SEO Tag Audit Report",40,i),i+=20,t.setFontSize(10),t.text(`Generated: ${new Date().toLocaleString()}`,40,i),i+=14,t.text(`Last Scan: ${h?new Date(h).toLocaleString():"N/A"}`,40,i),i+=14,t.text(`Compliance: ${v}%   Total: ${o.total} (Public: ${n}, Utility: ${x})`,40,i),i+=14,t.text(`Pass: ${o.pass}   Warnings: ${o.warning}   Fail: ${o.fail}   Missing canonical: ${o.missingCanonical}   Missing noindex: ${o.missingNoindex}`,40,i),i+=20,t.setFontSize(9),t.setFont("helvetica","bold");const g=[{label:"Route",x:40,w:130},{label:"Type",x:175,w:45},{label:"Status",x:225,w:50},{label:"Canonical",x:280,w:170},{label:"Robots",x:455,w:80},{label:"Issues",x:540,w:110},{label:"Suggested Fix",x:655,w:125}];g.forEach(p=>t.text(p.label,p.x,i)),i+=4,t.line(40,i,c-40,i),i+=12,t.setFont("helvetica","normal");const l=(p,k)=>t.splitTextToSize(p||"-",k);s.forEach(p=>{const k=[l(`${p.name}
3${p.path}`,g[0].w),l(p.kind,g[1].w),l(p.status.toUpperCase(),g[2].w),l(p.canonical||"-",g[3].w),l(p.robots||"-",g[4].w),l(p.issues.join("; ")||"OK",g[5].w),l(p.suggestions.join(" • ")||"—",g[6].w)],A=Math.max(...k.map(C=>C.length))*10+4;i+A>u-40&&(t.addPage(),i=40),k.forEach((C,D)=>t.text(C,g[D].x,i)),i+=A});const L=new Date().toISOString().split("T")[0];t.save(`seo-tag-audit-${L}.pdf`)};return e.jsxs(y,{children:[e.jsx(M,{children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsxs(H,{
3className:"flex items-center gap-2",children:[e.jsx(G,{className:"h-5 w-5"}),"SEO Tag Audit — Canonical & Noindex"]}),e.jsx(U,{children:"Scans every public and utility route for missing canonical tags and noindex directives. Auto-refreshes every 5 minutes."})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(R,{onClick:P,disabled:!s.length,size:"sm",variant:"outline",children:[e.jsx(_,{className:"h-4 w-4 mr-2"}),"CSV"]}),e.jsxs(R,{onClick:F,disabled:!s.length,size:"sm",variant:"outline",children:[e.jsx(J,{className:"h-4 w-4 mr-2"}),"PDF"]}),e.jsxs(R,{onClick:j,disabled:d,size:"sm",children:[e.jsx(K,{className:`h-4 w-4 mr-2 ${d?"animate-spin":""}`}),d?"Scanning...":"Re-scan"]})]})]})}),e.jsxs(B,{children:[d&&e.jsxs("div",{className:"space-y-2 mb-6",children:[e.jsxs("div",{className:"flex justify-between text-sm text-muted-foreground",children:[e.jsxs("span",{children:["Scanning ",w.length," routes…"]}),e.jsxs("span",{children:[a,"%"]})]}),e.jsx(z,{value:a})]}),s.length>0&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-5 gap-3 mb-6",children:[e.jsxs(y,{className:"p-3",children:[e.jsxs("div",{className:"text-2xl font-bold",children:[v,"%"]}),e.jsx("div",{className:"text-xs text-muted-foreground",children:"Compliance"})]}),e.jsxs(y,{className:"p-3",children:[e.jsx("div",{className:"text-2xl font-bold text-green-600",children:o.pass}),e.jsx("div",{className:"text-xs text-muted-foreground",children:"Passing"})]}),e.jsxs(y,{className:"p-3",children:[e.jsx("div",{className:"text-2xl font-bold text-red-600",children:o.fail}),e.jsx("div",{className:"text-xs text-muted-foreground",children:"Failures"})]}),e.jsxs(y,{className:"p-3",children:[e.jsx("div",{className:"text-2xl font-bold text-red-600",children:o.missingCanonical}),e.jsx("div",{className:"text-xs text-muted-foreground",children:"Missing canonical"})]}),e.jsxs(y,{className:"p-3",children:[e.jsx("div",{className:"text-2xl font-bold text-red-600",children:o.missingNoindex}),e.jsx("div",{className:"text-xs text-muted-foreground",children:"Missing noindex"})]})]}),h&&e.jsxs("p",{className:"text-xs text-muted-foreground mb-3",children:["Last scan: ",new Date(h).toLocaleString()]}),e.jsx(V,{className:"h-[420px] rounded-md border",children:e.jsx("div",{className:"p-3",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"sticky top-0 bg-background",children:e.jsxs("tr",{className:"border-b",children:[e.jsx("th",{className:"text-left py-2 px-2 font-medium",children:"Route"}),e.jsx("th",{className:"text-left py-2 px-2 font-medium",children:"Type"}),e.jsx("th",{className:"text-left py-2 px-2 font-medium",children:"Canonical"}),e.jsx("th",{className:"text-left py-2 px-2 font-medium",children:"Robots"}),e.jsx("th",{className:"text-left py-2 px-2 font-medium",children:"Issues"}),e.jsx("th",{className:"text-left py-2 px-2 font-medium",children:"Suggested Fix"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{className:"border-b hover:bg-muted/40",children:[e.jsxs("td",{className:"py-2 px-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(I,{status:t.status}),e.jsx("a",{href:t.path,target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:t.name})]}),e.jsx("div",{className:"text-xs text-muted-foreground ml-6",children:t.path})]}),e.jsx("td",{className:"py-2 px-2",children:e.jsx(E,{variant:t.kind==="public"?"default":"secondary",children:t.kind})}),e.jsx("td",{className:"py-2 px-2",children:t.canonical?e.jsx("span",{className:"text-xs text-muted-foreground break-all",children:t.canonical}):e.jsx(E,{variant:"outline",className:"bg-red-500/10 text-red-600 border-red-500/20",children:"Missing"})}),e.jsx("td",{className:"py-2 px-2",children:t.robots?e.jsx("span",{className:"text-xs",children:t.robots}):e.jsx("span",{className:"text-xs text-muted-foreground",children:"—"})}),e.jsx("td",{className:"py-2 px-2",children:t.issues.length===0?e.jsx("span",{className:"text-xs text-green-600",children:"OK"}):e.jsx("ul",{className:"text-xs text-red-600 space-y-0.5",children:t.issues.map(c=>e.jsxs("li",{children:["• ",c]},c))})}),e.jsx("td",{className:"py-2 px-2 align-top",children:t.suggestions.length===0?e.jsx("span",{className:"text-xs text-muted-foreground",children:"—"}):e.jsx("ul",{className:"text-xs space-y-1 max-w-[320px]",children:t.suggestions.map((c,u)=>e.jsx("li",{className:"text-foreground",children:e.jsx("code",{className:"text-[11px] bg-muted px-1 py-0.5 rounded break-all",children:c})},u))})})]},t.path))})]})})})]}),s.length===0&&!d&&e.jsx("div",{className:"text-center py-8 text-muted-foreground",children:'Click "Re-scan" to audit all routes.'})]})]})};export{Qe as SEOTagAudit,Qe 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.